Skip to content

Commit 7a90e45

Browse files
authored
feat(clients): add saveObjects, deleteObjects and partialUpdateObjects helpers (#3180)
1 parent 0d5cea7 commit 7a90e45

File tree

16 files changed

+713
-43
lines changed

16 files changed

+713
-43
lines changed

clients/algoliasearch-client-csharp/algoliasearch/Utils/SearchClientExtensions.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,50 @@ private static int NextDelay(int retryCount)
532532
return Math.Min(retryCount * 200, 5000);
533533
}
534534

535+
/// <summary>
536+
/// Helper: Saves the given array of objects in the given index. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it.
537+
/// </summary>
538+
/// <param name="indexName">The index in which to perform the request.</param>
539+
/// <param name="objects">The list of `objects` to store in the given Algolia `indexName`.</param>
540+
/// <param name="options">Add extra http header or query parameters to Algolia.</param>
541+
/// <param name="cancellationToken">Cancellation Token to cancel the request.</param>
542+
/// <typeparam name="T"></typeparam>
543+
public async Task<List<BatchResponse>> SaveObjectsAsync<T>(string indexName, IEnumerable<T> objects,
544+
RequestOptions options = null,
545+
CancellationToken cancellationToken = default) where T : class
546+
{
547+
return await ChunkedBatchAsync(indexName, objects, Action.AddObject, 1000, options, cancellationToken).ConfigureAwait(false);
548+
}
549+
550+
/// <summary>
551+
/// Helper: Deletes every records for the given objectIDs. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objectIDs in it.
552+
/// </summary>
553+
/// <param name="indexName">The index in which to perform the request.</param>
554+
/// <param name="objectIDs">The list of `objectIDs` to remove from the given Algolia `indexName`.</param>
555+
/// <param name="options">Add extra http header or query parameters to Algolia.</param>
556+
/// <param name="cancellationToken">Cancellation Token to cancel the request.</param>
557+
public async Task<List<BatchResponse>> DeleteObjects(string indexName, IEnumerable<String> objectIDs,
558+
RequestOptions options = null,
559+
CancellationToken cancellationToken = default)
560+
{
561+
return await ChunkedBatchAsync(indexName, objectIDs.Select(id => new { objectID = id }), Action.DeleteObject, 1000, options, cancellationToken).ConfigureAwait(false);
562+
}
563+
564+
/// <summary>
565+
/// Helper: Replaces object content of all the given objects according to their respective `objectID` field. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it.
566+
/// </summary>
567+
/// <param name="indexName">The index in which to perform the request.</param>
568+
/// <param name="objects">The list of `objects` to update in the given Algolia `indexName`.</param>
569+
/// <param name="createIfNotExists">To be provided if non-existing objects are passed, otherwise, the call will fail.</param>
570+
/// <param name="options">Add extra http header or query parameters to Algolia.</param>
571+
/// <param name="cancellationToken">Cancellation Token to cancel the request.</param>
572+
public async Task<List<BatchResponse>> PartialUpdateObjects<T>(string indexName, IEnumerable<T> objects, bool createIfNotExists,
573+
RequestOptions options = null,
574+
CancellationToken cancellationToken = default) where T : class
575+
{
576+
return await ChunkedBatchAsync(indexName, objects, createIfNotExists ? Action.PartialUpdateObject : Action.PartialUpdateObjectNoCreate, 1000, options, cancellationToken).ConfigureAwait(false);
577+
}
578+
535579
private static async Task<List<TU>> CreateIterable<TU>(Func<TU, Task<TU>> executeQuery,
536580
Func<TU, bool> stopCondition)
537581
{

clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/extensions/SearchClient.kt

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import io.ktor.util.*
1111
import kotlinx.datetime.Clock
1212
import kotlinx.datetime.Instant
1313
import kotlinx.serialization.json.JsonObject
14+
import kotlinx.serialization.json.*
1415
import kotlin.random.Random
1516
import kotlin.time.Duration
1617
import kotlin.time.Duration.Companion.milliseconds
@@ -316,6 +317,80 @@ public suspend fun SearchClient.chunkedBatch(
316317
return tasks
317318
}
318319

320+
/**
321+
* Helper: Saves the given array of objects in the given index. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it.
322+
*
323+
* @param indexName The index in which to perform the request.
324+
* @param objects The list of objects to index.
325+
* @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions.
326+
* @return The list of responses from the batch requests.
327+
*
328+
*/
329+
public suspend fun SearchClient.saveObjects(
330+
indexName: String,
331+
objects: List<JsonObject>,
332+
requestOptions: RequestOptions? = null,
333+
): List<BatchResponse> {
334+
return this.chunkedBatch(
335+
indexName = indexName,
336+
objects = objects,
337+
action = Action.AddObject,
338+
waitForTask = false,
339+
batchSize = 1000,
340+
requestOptions = requestOptions,
341+
)
342+
}
343+
344+
/**
345+
* Helper: Deletes every records for the given objectIDs. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objectIDs in it.
346+
*
347+
* @param indexName The index in which to perform the request.
348+
* @param objectIDs The list of objectIDs to delete from the index.
349+
* @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions.
350+
* @return The list of responses from the batch requests.
351+
*
352+
*/
353+
public suspend fun SearchClient.deleteObjects(
354+
indexName: String,
355+
objectIDs: List<String>,
356+
requestOptions: RequestOptions? = null,
357+
): List<BatchResponse> {
358+
return this.chunkedBatch(
359+
indexName = indexName,
360+
objects = objectIDs.map { id -> JsonObject(mapOf("objectID" to Json.encodeToJsonElement(id))) },
361+
action = Action.DeleteObject,
362+
waitForTask = false,
363+
batchSize = 1000,
364+
requestOptions = requestOptions,
365+
)
366+
}
367+
368+
/**
369+
* Helper: Replaces object content of all the given objects according to their respective `objectID` field. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it.
370+
*
371+
* @param indexName The index in which to perform the request.
372+
* @param objectIDs The list of objects to update in the index.
373+
* @param createIfNotExists To be provided if non-existing objects are passed, otherwise, the call will fail..
374+
* @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions.
375+
* @return The list of responses from the batch requests.
376+
*
377+
*/
378+
public suspend fun SearchClient.partialUpdateObjects(
379+
indexName: String,
380+
objects: List<JsonObject>,
381+
createIfNotExists: Boolean,
382+
requestOptions: RequestOptions? = null,
383+
): List<BatchResponse> {
384+
return this.chunkedBatch(
385+
indexName = indexName,
386+
objects = objects,
387+
action = if (createIfNotExists) Action.PartialUpdateObject else Action.PartialUpdateObjectNoCreate,
388+
waitForTask = false,
389+
batchSize = 1000,
390+
requestOptions = requestOptions,
391+
)
392+
}
393+
319394
/**
320395
* Push a new set of objects and remove all previous ones. Settings, synonyms and query rules are untouched.
321396
* Replace all objects in an index without any downtime.

clients/algoliasearch-client-scala/src/main/scala/algoliasearch/extension/package.scala

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,10 @@ package object extension {
197197
*
198198
* @param indexName
199199
* The index in which to perform the request.
200-
* @param records
201-
* The list of records to replace.
200+
* @param objects
201+
* The list of objects to save.
202202
* @param action
203-
* The action to perform on the records.
203+
* The action to perform on the objects.
204204
* @param waitForTasks
205205
* Whether to wait for the tasks to complete.
206206
* @param batchSize
@@ -212,14 +212,14 @@ package object extension {
212212
*/
213213
def chunkedBatch(
214214
indexName: String,
215-
records: Seq[Any],
215+
objects: Seq[Any],
216216
action: Action = Action.AddObject,
217217
waitForTasks: Boolean,
218218
batchSize: Int = 1000,
219219
requestOptions: Option[RequestOptions] = None
220220
)(implicit ec: ExecutionContext): Future[Seq[BatchResponse]] = {
221221
var futures = Seq.empty[Future[BatchResponse]]
222-
records.grouped(batchSize).foreach { chunk =>
222+
objects.grouped(batchSize).foreach { chunk =>
223223
val requests = chunk.map { record =>
224224
BatchRequest(action = action, body = record)
225225
}
@@ -244,6 +244,66 @@ package object extension {
244244
responses
245245
}
246246

247+
/** Helper: Saves the given array of objects in the given index. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it.
248+
*
249+
* @param indexName
250+
* The index in which to perform the request.
251+
* @param objects
252+
* The list of objects to save.
253+
* @param requestOptions
254+
* Additional request configuration.
255+
* @return
256+
* A future containing the response of the batch operations.
257+
*/
258+
def saveObjects(
259+
indexName: String,
260+
objects: Seq[Any],
261+
requestOptions: Option[RequestOptions] = None
262+
)(implicit ec: ExecutionContext): Future[Seq[BatchResponse]] = {
263+
chunkedBatch(indexName, objects, Action.AddObject, false, 1000, requestOptions)
264+
}
265+
266+
/** Helper: Deletes every objects for the given objectIDs. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objectIDs in it.
267+
*
268+
* @param indexName
269+
* The index in which to perform the request.
270+
* @param objectIDs
271+
* The list of objectIDs to delete.
272+
* @param requestOptions
273+
* Additional request configuration.
274+
* @return
275+
* A future containing the response of the batch operations.
276+
*/
277+
def deleteObjects(
278+
indexName: String,
279+
objectIDs: Seq[String],
280+
requestOptions: Option[RequestOptions] = None
281+
)(implicit ec: ExecutionContext): Future[Seq[BatchResponse]] = {
282+
chunkedBatch(indexName, objectIDs.map(id => new { val objectID: String = id }), Action.DeleteObject, false, 1000, requestOptions)
283+
}
284+
285+
/** Helper: Replaces object content of all the given objects according to their respective `objectID` field. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it.
286+
*
287+
* @param indexName
288+
* The index in which to perform the request.
289+
* @param objects
290+
* The list of objects to save.
291+
* @param createIfNotExists
292+
* To be provided if non-existing objects are passed, otherwise, the call will fail.
293+
* @param requestOptions
294+
* Additional request configuration.
295+
* @return
296+
* A future containing the response of the batch operations.
297+
*/
298+
def partialUpdateObjects(
299+
indexName: String,
300+
objects: Seq[Any],
301+
createIfNotExists: Boolean,
302+
requestOptions: Option[RequestOptions] = None
303+
)(implicit ec: ExecutionContext): Future[Seq[BatchResponse]] = {
304+
chunkedBatch(indexName, objects, if (createIfNotExists) Action.PartialUpdateObject else Action.PartialUpdateObjectNoCreate, false, 1000, requestOptions)
305+
}
306+
247307
/** Push a new set of objects and remove all previous ones. Settings, synonyms and query rules are untouched.
248308
* Replace all objects in an index without any downtime. Internally, this method copies the existing index
249309
* settings, synonyms and query rules and indexes all passed objects. Finally, the temporary one replaces the
@@ -254,8 +314,8 @@ package object extension {
254314
*
255315
* @param indexName
256316
* The index in which to perform the request.
257-
* @param records
258-
* The list of records to replace.
317+
* @param objects
318+
* The list of objects to replace.
259319
* @param batchSize
260320
* The size of the batch. Default is 1000.
261321
* @param requestOptions
@@ -265,11 +325,11 @@ package object extension {
265325
*/
266326
def replaceAllObjects(
267327
indexName: String,
268-
records: Seq[Any],
328+
objects: Seq[Any],
269329
batchSize: Int = 1000,
270330
requestOptions: Option[RequestOptions] = None
271331
)(implicit ec: ExecutionContext): Future[ReplaceAllObjectsResponse] = {
272-
val requests = records.map { record =>
332+
val requests = objects.map { record =>
273333
BatchRequest(action = Action.AddObject, body = record)
274334
}
275335
val tmpIndexName = s"${indexName}_tmp_${scala.util.Random.nextInt(100)}"
@@ -287,7 +347,7 @@ package object extension {
287347

288348
batchResponses <- chunkedBatch(
289349
indexName = tmpIndexName,
290-
records = records,
350+
objects = objects,
291351
action = Action.AddObject,
292352
waitForTasks = true,
293353
batchSize = batchSize,

clients/algoliasearch-client-swift/Sources/Search/Extra/SearchClientExtension.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,71 @@ public extension SearchClient {
456456
return responses
457457
}
458458

459+
/// Helper: Saves the given array of objects in the given index. The `chunkedBatch` helper is used under the hood,
460+
/// which creates a `batch` requests with at most 1000 objects in it.
461+
/// - parameter indexName: The name of the index where to save the objects
462+
/// - parameter objects: The new objects
463+
/// - parameter requestOptions: The request options
464+
/// - returns: [BatchResponse]
465+
func saveObjects(
466+
indexName: String,
467+
objects: [some Encodable],
468+
requestOptions: RequestOptions? = nil
469+
) async throws -> [BatchResponse] {
470+
try await self.chunkedBatch(
471+
indexName: indexName,
472+
objects: objects,
473+
action: .addObject,
474+
waitForTasks: false,
475+
batchSize: 1000,
476+
requestOptions: requestOptions
477+
)
478+
}
479+
480+
/// Helper: Deletes every records for the given objectIDs. The `chunkedBatch` helper is used under the hood, which
481+
/// creates a `batch` requests with at most 1000 objectIDs in it.
482+
/// - parameter indexName: The name of the index to delete objectIDs from
483+
/// - parameter objectIDs: The objectIDs to delete
484+
/// - parameter requestOptions: The request options
485+
/// - returns: [BatchResponse]
486+
func deleteObjects(
487+
indexName: String,
488+
objectIDs: [String],
489+
requestOptions: RequestOptions? = nil
490+
) async throws -> [BatchResponse] {
491+
try await self.chunkedBatch(
492+
indexName: indexName,
493+
objects: objectIDs.map { AnyCodable(["objectID": $0]) },
494+
action: .deleteObject,
495+
waitForTasks: false,
496+
batchSize: 1000,
497+
requestOptions: requestOptions
498+
)
499+
}
500+
501+
/// Helper: Replaces object content of all the given objects according to their respective `objectID` field. The
502+
/// `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it.
503+
/// - parameter indexName: The name of the index where to update the objects
504+
/// - parameter objects: The objects to update
505+
/// - parameter createIfNotExist: To be provided if non-existing objects are passed, otherwise, the call will fail..
506+
/// - parameter requestOptions: The request options
507+
/// - returns: [BatchResponse]
508+
func partialUpdateObjects(
509+
indexName: String,
510+
objects: [some Encodable],
511+
createIfNotExist: Bool = false,
512+
requestOptions: RequestOptions? = nil
513+
) async throws -> [BatchResponse] {
514+
try await self.chunkedBatch(
515+
indexName: indexName,
516+
objects: objects,
517+
action: createIfNotExist ? .partialUpdateObject : .partialUpdateObjectNoCreate,
518+
waitForTasks: false,
519+
batchSize: 1000,
520+
requestOptions: requestOptions
521+
)
522+
}
523+
459524
/// Replace all objects in an index
460525
///
461526
/// See https://api-clients-automation.netlify.app/docs/contributing/add-new-api-client#5-helpers for implementation
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
method:
2+
post:
3+
x-helper: true
4+
tags:
5+
- Records
6+
operationId: deleteObjects
7+
summary: Deletes every records for the given objectIDs
8+
description: |
9+
Helper: Deletes every records for the given objectIDs. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objectIDs in it.
10+
parameters:
11+
- in: query
12+
name: indexName
13+
description: The `indexName` to delete `objectIDs` from.
14+
required: true
15+
schema:
16+
type: string
17+
- in: query
18+
name: objectIDs
19+
description: The objectIDs to delete.
20+
required: true
21+
schema:
22+
type: array
23+
items:
24+
type: string
25+
responses:
26+
'200':
27+
description: OK
28+
content:
29+
application/json:
30+
schema:
31+
type: array
32+
items:
33+
$ref: '../paths/objects/common/schemas.yml#/batchResponse'
34+
'400':
35+
$ref: '../../common/responses/IndexNotFound.yml'

0 commit comments

Comments
 (0)