Skip to content

Commit 407c6dd

Browse files
fix(clients): allow chunked requests on WithTransformation methods (generated)
algolia/api-clients-automation#5011 Co-authored-by: algolia-bot <[email protected]> Co-authored-by: Clément Vannicatte <[email protected]>
1 parent 0441852 commit 407c6dd

File tree

7 files changed

+187
-513
lines changed

7 files changed

+187
-513
lines changed

packages/algoliasearch/__tests__/algoliasearch.common.test.ts

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -168,86 +168,6 @@ describe('api', () => {
168168
}),
169169
).rejects.toThrow('`transformation.region` must be provided at client instantiation before calling this method.');
170170
});
171-
172-
test('exposes the transformation methods at the root of the client', async () => {
173-
const ingestionClient = algoliasearch('APP_ID', 'API_KEY', {
174-
requester: browserEchoRequester(),
175-
transformation: { region: 'us' },
176-
});
177-
178-
expect(ingestionClient.saveObjectsWithTransformation).not.toBeUndefined();
179-
180-
let res = (await ingestionClient.saveObjectsWithTransformation({
181-
indexName: 'foo',
182-
objects: [{ objectID: 'bar', baz: 42 }],
183-
waitForTasks: true,
184-
})) as unknown as EchoResponse;
185-
186-
expect(res.headers).toEqual(
187-
expect.objectContaining({
188-
'x-algolia-application-id': 'APP_ID',
189-
'x-algolia-api-key': 'API_KEY',
190-
}),
191-
);
192-
expect(res.url.startsWith('https://data.us.algolia.com/1/push/foo?watch=true')).toBeTruthy();
193-
expect(res.data).toEqual({
194-
action: 'addObject',
195-
records: [
196-
{
197-
baz: 42,
198-
objectID: 'bar',
199-
},
200-
],
201-
});
202-
expect(ingestionClient.partialUpdateObjectsWithTransformation).not.toBeUndefined();
203-
204-
res = (await ingestionClient.partialUpdateObjectsWithTransformation({
205-
indexName: 'foo',
206-
objects: [{ objectID: 'bar', baz: 42 }],
207-
waitForTasks: true,
208-
createIfNotExists: true,
209-
})) as unknown as EchoResponse;
210-
211-
expect(res.headers).toEqual(
212-
expect.objectContaining({
213-
'x-algolia-application-id': 'APP_ID',
214-
'x-algolia-api-key': 'API_KEY',
215-
}),
216-
);
217-
expect(res.url.startsWith('https://data.us.algolia.com/1/push/foo?watch=true')).toBeTruthy();
218-
expect(res.data).toEqual({
219-
action: 'partialUpdateObject',
220-
records: [
221-
{
222-
baz: 42,
223-
objectID: 'bar',
224-
},
225-
],
226-
});
227-
228-
res = (await ingestionClient.partialUpdateObjectsWithTransformation({
229-
indexName: 'foo',
230-
objects: [{ objectID: 'bar', baz: 42 }],
231-
waitForTasks: true,
232-
})) as unknown as EchoResponse;
233-
234-
expect(res.headers).toEqual(
235-
expect.objectContaining({
236-
'x-algolia-application-id': 'APP_ID',
237-
'x-algolia-api-key': 'API_KEY',
238-
}),
239-
);
240-
expect(res.url.startsWith('https://data.us.algolia.com/1/push/foo?watch=true')).toBeTruthy();
241-
expect(res.data).toEqual({
242-
action: 'partialUpdateObjectNoCreate',
243-
records: [
244-
{
245-
baz: 42,
246-
objectID: 'bar',
247-
},
248-
],
249-
});
250-
});
251171
});
252172
});
253173

packages/algoliasearch/builds/browser.ts

Lines changed: 19 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
22

3-
import type { ApiError, ClientOptions, RequestOptions } from '@algolia/client-common';
4-
import { createIterablePromise } from '@algolia/client-common';
3+
import type { ClientOptions, RequestOptions } from '@algolia/client-common';
54

65
import type { AbtestingClient } from '@algolia/client-abtesting';
76
import { abtestingClient } from '@algolia/client-abtesting';
@@ -23,13 +22,12 @@ import type { RecommendClient } from '@algolia/recommend';
2322
import { recommendClient } from '@algolia/recommend';
2423

2524
import type {
26-
ChunkedBatchOptions,
2725
PartialUpdateObjectsOptions,
2826
ReplaceAllObjectsOptions,
2927
ReplaceAllObjectsWithTransformationResponse,
3028
SaveObjectsOptions,
3129
} from '@algolia/client-search';
32-
import type { PushTaskRecords, WatchResponse } from '@algolia/ingestion';
30+
import type { WatchResponse } from '@algolia/ingestion';
3331

3432
import type {
3533
AbtestingRegionOptions,
@@ -65,12 +63,12 @@ export type Algoliasearch = SearchClient & {
6563
* @param saveObjects.objects - The array of `objects` to store in the given Algolia `indexName`.
6664
* @param saveObjects.batchSize - The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000.
6765
* @param saveObjects.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.
68-
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `batch` method and merged with the transporter requestOptions.
66+
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `push` method and merged with the transporter requestOptions.
6967
*/
7068
saveObjectsWithTransformation: (
7169
options: SaveObjectsOptions,
7270
requestOptions?: RequestOptions | undefined,
73-
) => Promise<WatchResponse>;
71+
) => Promise<Array<WatchResponse>>;
7472

7573
/**
7674
* Helper: Similar to the `partialUpdateObjects` method but requires a Push connector (https://www.algolia.com/doc/guides/sending-and-managing-data/send-and-update-your-data/connectors/push/) to be created first, in order to transform records before indexing them to Algolia. The `region` must have been passed to the client instantiation method.
@@ -82,12 +80,12 @@ export type Algoliasearch = SearchClient & {
8280
* @param partialUpdateObjects.createIfNotExists - To be provided if non-existing objects are passed, otherwise, the call will fail..
8381
* @param partialUpdateObjects.batchSize - The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000.
8482
* @param partialUpdateObjects.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.
85-
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `getTask` method and merged with the transporter requestOptions.
83+
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `push` method and merged with the transporter requestOptions.
8684
*/
8785
partialUpdateObjectsWithTransformation: (
8886
options: PartialUpdateObjectsOptions,
8987
requestOptions?: RequestOptions | undefined,
90-
) => Promise<WatchResponse>;
88+
) => Promise<Array<WatchResponse>>;
9189

9290
/**
9391
* Helper: Similar to the `replaceAllObjects` method but requires a Push connector (https://www.algolia.com/doc/guides/sending-and-managing-data/send-and-update-your-data/connectors/push/) to be created first, in order to transform records before indexing them to Algolia. The `region` must have been passed to the client instantiation method.
@@ -104,20 +102,6 @@ export type Algoliasearch = SearchClient & {
104102
options: ReplaceAllObjectsOptions,
105103
requestOptions?: RequestOptions | undefined,
106104
) => Promise<ReplaceAllObjectsWithTransformationResponse>;
107-
108-
/**
109-
* Helper: Chunks the given `objects` list in subset of 1000 elements max in order to make it fit in `push` requests by leveraging the Transformation pipeline setup in the Push connector (https://www.algolia.com/doc/guides/sending-and-managing-data/send-and-update-your-data/connectors/push/).
110-
*
111-
* @summary Helper: Chunks the given `objects` list in subset of 1000 elements max in order to make it fit in `batch` requests.
112-
* @param chunkedPush - The `chunkedPush` object.
113-
* @param chunkedPush.indexName - The `indexName` to replace `objects` in.
114-
* @param chunkedPush.objects - The array of `objects` to store in the given Algolia `indexName`.
115-
* @param chunkedPush.action - The `batch` `action` to perform on the given array of `objects`, defaults to `addObject`.
116-
* @param chunkedPush.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.
117-
* @param chunkedPush.batchSize - The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000.
118-
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `getEvent` method and merged with the transporter requestOptions.
119-
*/
120-
chunkedPush: (options: ChunkedBatchOptions, requestOptions?: RequestOptions) => Promise<Array<WatchResponse>>;
121105
};
122106

123107
export type TransformationOptions = {
@@ -158,7 +142,10 @@ export function algoliasearch(
158142
return {
159143
...client,
160144

161-
async saveObjectsWithTransformation({ indexName, objects, waitForTasks }, requestOptions): Promise<WatchResponse> {
145+
async saveObjectsWithTransformation(
146+
{ indexName, objects, waitForTasks },
147+
requestOptions,
148+
): Promise<Array<WatchResponse>> {
162149
if (!ingestionTransporter) {
163150
throw new Error('`transformation.region` must be provided at client instantiation before calling this method.');
164151
}
@@ -167,23 +154,16 @@ export function algoliasearch(
167154
throw new Error('`region` must be provided when leveraging the transformation pipeline');
168155
}
169156

170-
return ingestionTransporter?.push(
171-
{
172-
indexName,
173-
watch: waitForTasks,
174-
pushTaskPayload: {
175-
action: 'addObject',
176-
records: objects as PushTaskRecords[],
177-
},
178-
},
157+
return ingestionTransporter.chunkedPush(
158+
{ indexName, objects, action: 'addObject', waitForTasks },
179159
requestOptions,
180160
);
181161
},
182162

183163
async partialUpdateObjectsWithTransformation(
184164
{ indexName, objects, createIfNotExists, waitForTasks },
185165
requestOptions,
186-
): Promise<WatchResponse> {
166+
): Promise<Array<WatchResponse>> {
187167
if (!ingestionTransporter) {
188168
throw new Error('`transformation.region` must be provided at client instantiation before calling this method.');
189169
}
@@ -192,86 +172,17 @@ export function algoliasearch(
192172
throw new Error('`region` must be provided when leveraging the transformation pipeline');
193173
}
194174

195-
return ingestionTransporter?.push(
175+
return ingestionTransporter.chunkedPush(
196176
{
197177
indexName,
198-
watch: waitForTasks,
199-
pushTaskPayload: {
200-
action: createIfNotExists ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate',
201-
records: objects as PushTaskRecords[],
202-
},
178+
objects,
179+
action: createIfNotExists ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate',
180+
waitForTasks,
203181
},
204182
requestOptions,
205183
);
206184
},
207185

208-
async chunkedPush(
209-
{ indexName, objects, action = 'addObject', waitForTasks, batchSize = 1000 }: ChunkedBatchOptions,
210-
requestOptions?: RequestOptions,
211-
): Promise<Array<WatchResponse>> {
212-
if (!ingestionTransporter) {
213-
throw new Error('`transformation.region` must be provided at client instantiation before calling this method.');
214-
}
215-
216-
if (!options?.transformation?.region) {
217-
throw new Error('`region` must be provided when leveraging the transformation pipeline');
218-
}
219-
220-
let records: Array<PushTaskRecords> = [];
221-
const responses: Array<WatchResponse> = [];
222-
223-
const objectEntries = objects.entries();
224-
for (const [i, obj] of objectEntries) {
225-
records.push(obj as PushTaskRecords);
226-
if (records.length === batchSize || i === objects.length - 1) {
227-
responses.push(
228-
await ingestionTransporter.push(
229-
{ indexName, pushTaskPayload: { action, records }, watch: waitForTasks },
230-
requestOptions,
231-
),
232-
);
233-
records = [];
234-
}
235-
}
236-
237-
let retryCount = 0;
238-
239-
if (waitForTasks) {
240-
for (const resp of responses) {
241-
if (!resp.eventID) {
242-
throw new Error('received unexpected response from the push endpoint, eventID must not be undefined');
243-
}
244-
245-
await createIterablePromise({
246-
func: async () => {
247-
if (resp.eventID === undefined || !resp.eventID) {
248-
throw new Error('received unexpected response from the push endpoint, eventID must not be undefined');
249-
}
250-
251-
return ingestionTransporter
252-
.getEvent({ runID: resp.runID, eventID: resp.eventID })
253-
.catch((error: ApiError) => {
254-
if (error.status === 404) {
255-
return undefined;
256-
}
257-
258-
throw error;
259-
});
260-
},
261-
validate: (response) => response !== undefined,
262-
aggregator: () => (retryCount += 1),
263-
error: {
264-
validate: () => retryCount >= 50,
265-
message: () => `The maximum number of retries exceeded. (${retryCount}/${50})`,
266-
},
267-
timeout: (): number => Math.min(retryCount * 500, 5000),
268-
});
269-
}
270-
}
271-
272-
return responses;
273-
},
274-
275186
async replaceAllObjectsWithTransformation(
276187
{ indexName, objects, batchSize, scopes }: ReplaceAllObjectsOptions,
277188
requestOptions?: RequestOptions | undefined,
@@ -304,8 +215,8 @@ export function algoliasearch(
304215
requestOptions,
305216
);
306217

307-
const watchResponses = await this.chunkedPush(
308-
{ indexName: tmpIndexName, objects, waitForTasks: true, batchSize },
218+
const watchResponses = await ingestionTransporter.chunkedPush(
219+
{ indexName: tmpIndexName, objects, waitForTasks: true, batchSize, referenceIndexName: indexName },
309220
requestOptions,
310221
);
311222

0 commit comments

Comments
 (0)