Skip to content

Commit 69ecf92

Browse files
committed
Change UpsertAsync return type to IReadOnlyList<TKey>
Closes microsoft#10692
1 parent 4fc76f2 commit 69ecf92

File tree

44 files changed

+143
-198
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+143
-198
lines changed

dotnet/samples/Concepts/Memory/VectorStoreEmbeddingGeneration/TextEmbeddingVectorStoreRecordCollection.cs

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
using System.Linq.Expressions;
44
using System.Reflection;
5-
using System.Runtime.CompilerServices;
65
using Microsoft.Extensions.VectorData;
76
using Microsoft.SemanticKernel.Embeddings;
87

@@ -110,15 +109,11 @@ public async Task<TKey> UpsertAsync(TRecord record, CancellationToken cancellati
110109
}
111110

112111
/// <inheritdoc />
113-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
112+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
114113
{
115114
var recordWithEmbeddingsTasks = records.Select(r => this.AddEmbeddingsAsync(r, cancellationToken));
116115
var recordWithEmbeddings = await Task.WhenAll(recordWithEmbeddingsTasks).ConfigureAwait(false);
117-
var upsertResults = this._decoratedVectorStoreRecordCollection.UpsertAsync(recordWithEmbeddings, cancellationToken);
118-
await foreach (var upsertResult in upsertResults.ConfigureAwait(false))
119-
{
120-
yield return upsertResult;
121-
}
116+
return await this._decoratedVectorStoreRecordCollection.UpsertAsync(recordWithEmbeddings, cancellationToken);
122117
}
123118

124119
/// <inheritdoc />

dotnet/samples/Concepts/Memory/VectorStore_EmbeddingGeneration.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task UseEmbeddingGenerationViaDecoratorAsync()
4545
await collection.CreateCollectionIfNotExistsAsync();
4646

4747
// Create and upsert glossary entries into the collection.
48-
await collection.UpsertAsync(CreateGlossaryEntries()).ToListAsync();
48+
await collection.UpsertAsync(CreateGlossaryEntries());
4949

5050
// Search the collection using a vectorizable text search.
5151
var search = collection as IVectorizableTextSearch<Glossary>;

dotnet/samples/Concepts/Optimization/FrugalGPTWithFilters.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public async Task OnPromptRenderAsync(PromptRenderContext context, Func<PromptRe
210210
var collection = vectorStore.GetCollection<string, ExampleRecord>(CollectionName);
211211
await collection.CreateCollectionIfNotExistsAsync(context.CancellationToken);
212212

213-
await collection.UpsertAsync(exampleRecords, cancellationToken: context.CancellationToken).ToListAsync(context.CancellationToken);
213+
await collection.UpsertAsync(exampleRecords, cancellationToken: context.CancellationToken);
214214

215215
// Generate embedding for original request.
216216
var requestEmbedding = await textEmbeddingGenerationService.GenerateEmbeddingAsync(request, cancellationToken: context.CancellationToken);

dotnet/samples/Concepts/Optimization/PluginSelectionWithFilters.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ public async Task SaveAsync(string collectionName, KernelPluginCollection plugin
341341
var collection = vectorStore.GetCollection<string, FunctionRecord>(collectionName);
342342
await collection.CreateCollectionIfNotExistsAsync(cancellationToken);
343343

344-
await collection.UpsertAsync(functionRecords, cancellationToken: cancellationToken).ToListAsync(cancellationToken);
344+
await collection.UpsertAsync(functionRecords, cancellationToken: cancellationToken);
345345
}
346346

347347
private static List<(KernelFunction Function, string TextToVectorize)> GetFunctionsData(KernelPluginCollection plugins)

dotnet/samples/Demos/VectorStoreRAG/DataLoader.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ public async Task LoadPdf(string pdfPath, int batchSize, int betweenBatchDelayIn
6666

6767
// Upsert the records into the vector store.
6868
var records = await Task.WhenAll(recordTasks).ConfigureAwait(false);
69-
var upsertedKeys = vectorStoreRecordCollection.UpsertAsync(records, cancellationToken: cancellationToken);
70-
await foreach (var key in upsertedKeys.ConfigureAwait(false))
69+
var upsertedKeys = await vectorStoreRecordCollection.UpsertAsync(records, cancellationToken: cancellationToken).ConfigureAwait(false);
70+
foreach (var key in upsertedKeys)
7171
{
7272
Console.WriteLine($"Upserted record '{key}' into VectorDB");
7373
}

dotnet/src/Connectors/Connectors.AzureAISearch.UnitTests/AzureAISearchVectorStoreRecordCollectionTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ public async Task CanUpsertManyRecordsAsync(bool useDefinition)
458458
// Act.
459459
var actual = await sut.UpsertAsync(
460460
[model1, model2],
461-
cancellationToken: this._testCancellationToken).ToListAsync();
461+
cancellationToken: this._testCancellationToken);
462462

463463
// Assert.
464464
Assert.NotNull(actual);

dotnet/src/Connectors/Connectors.AzureCosmosDBMongoDB.UnitTests/AzureCosmosDBMongoDBVectorStoreRecordCollectionTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ public async Task UpsertBatchReturnsRecordKeysAsync()
418418
"collection");
419419

420420
// Act
421-
var results = await sut.UpsertAsync([hotel1, hotel2, hotel3]).ToListAsync();
421+
var results = await sut.UpsertAsync([hotel1, hotel2, hotel3]);
422422

423423
// Assert
424424
Assert.NotNull(results);

dotnet/src/Connectors/Connectors.AzureCosmosDBNoSQL.UnitTests/AzureCosmosDBNoSQLVectorStoreRecordCollectionTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ public async Task UpsertBatchReturnsRecordKeysAsync()
469469
"collection");
470470

471471
// Act
472-
var results = await sut.UpsertAsync([hotel1, hotel2, hotel3]).ToListAsync();
472+
var results = await sut.UpsertAsync([hotel1, hotel2, hotel3]);
473473

474474
// Assert
475475
Assert.NotNull(results);

dotnet/src/Connectors/Connectors.InMemory.UnitTests/InMemoryVectorStoreRecordCollectionTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ public async Task CanUpsertManyRecordsAsync<TKey>(bool useDefinition, TKey testK
257257
// Act
258258
var actual = await sut.UpsertAsync(
259259
[record1, record2],
260-
cancellationToken: this._testCancellationToken).ToListAsync();
260+
cancellationToken: this._testCancellationToken);
261261

262262
// Assert
263263
Assert.NotNull(actual);

dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchVectorStoreRecordCollection.cs

+3-7
Original file line numberDiff line numberDiff line change
@@ -283,12 +283,12 @@ public async Task<TKey> UpsertAsync(TRecord record, CancellationToken cancellati
283283
}
284284

285285
/// <inheritdoc />
286-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
286+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
287287
{
288288
Verify.NotNull(records);
289289
if (!records.Any())
290290
{
291-
yield break;
291+
return [];
292292
}
293293

294294
// Create Options
@@ -297,11 +297,7 @@ public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [E
297297
// Upsert records
298298
var results = await this.MapToStorageModelAndUploadDocumentAsync(records, innerOptions, cancellationToken).ConfigureAwait(false);
299299

300-
// Get results
301-
foreach (var key in results.Value.Results.Select(x => x.Key))
302-
{
303-
yield return (TKey)(object)key;
304-
}
300+
return results.Value.Results.Select(x => (TKey)(object)x.Key).ToList();
305301
}
306302

307303
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBVectorStoreRecordCollection.cs

+2-9
Original file line numberDiff line numberDiff line change
@@ -247,20 +247,13 @@ await this._mongoCollection
247247
}
248248

249249
/// <inheritdoc />
250-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
250+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
251251
{
252252
Verify.NotNull(records);
253253

254254
var tasks = records.Select(record => this.UpsertAsync(record, cancellationToken));
255255
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
256-
257-
foreach (var result in results)
258-
{
259-
if (result is not null)
260-
{
261-
yield return (TKey)(object)result;
262-
}
263-
}
256+
return results.Where(r => r is not null).ToList();
264257
}
265258

266259
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLVectorStoreRecordCollection.cs

+2-10
Original file line numberDiff line numberDiff line change
@@ -286,22 +286,14 @@ await this.RunOperationAsync(OperationName, () =>
286286
}
287287

288288
/// <inheritdoc />
289-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
289+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
290290
{
291291
Verify.NotNull(records);
292292

293293
// TODO: Do proper bulk upsert rather than parallel single inserts, #11350
294294
var tasks = records.Select(record => this.UpsertAsync(record, cancellationToken));
295-
296295
var keys = await Task.WhenAll(tasks).ConfigureAwait(false);
297-
298-
foreach (var key in keys)
299-
{
300-
if (key is not null)
301-
{
302-
yield return key;
303-
}
304-
}
296+
return keys.Where(k => k is not null).ToList();
305297
}
306298

307299
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryVectorStoreRecordCollection.cs

+14-16
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,17 @@ public Task DeleteAsync(IEnumerable<TKey> keys, CancellationToken cancellationTo
232232

233233
/// <inheritdoc />
234234
public Task<TKey> UpsertAsync(TRecord record, CancellationToken cancellationToken = default)
235+
=> Task.FromResult(this.Upsert(record));
236+
237+
/// <inheritdoc />
238+
public Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
239+
{
240+
Verify.NotNull(records);
241+
242+
return Task.FromResult<IReadOnlyList<TKey>>(records.Select(this.Upsert).ToList());
243+
}
244+
245+
private TKey Upsert(TRecord record)
235246
{
236247
Verify.NotNull(record);
237248

@@ -240,24 +251,11 @@ public Task<TKey> UpsertAsync(TRecord record, CancellationToken cancellationToke
240251
var key = (TKey)this._keyResolver(record)!;
241252
collectionDictionary.AddOrUpdate(key!, record, (key, currentValue) => record);
242253

243-
return Task.FromResult(key!);
244-
}
245-
246-
/// <inheritdoc />
247-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
248-
{
249-
Verify.NotNull(records);
250-
251-
foreach (var record in records)
252-
{
253-
yield return await this.UpsertAsync(record, cancellationToken).ConfigureAwait(false);
254-
}
254+
return key!;
255255
}
256256

257257
/// <inheritdoc />
258-
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - Need to satisfy the interface which returns IAsyncEnumerable
259-
public async Task<VectorSearchResults<TRecord>> VectorizedSearchAsync<TVector>(TVector vector, int top, VectorSearchOptions<TRecord>? options = null, CancellationToken cancellationToken = default)
260-
#pragma warning restore CS1998
258+
public Task<VectorSearchResults<TRecord>> VectorizedSearchAsync<TVector>(TVector vector, int top, VectorSearchOptions<TRecord>? options = null, CancellationToken cancellationToken = default)
261259
{
262260
Verify.NotNull(vector);
263261
Verify.NotLessThan(top, 1);
@@ -315,7 +313,7 @@ public async Task<VectorSearchResults<TRecord>> VectorizedSearchAsync<TVector>(T
315313

316314
// Build the response.
317315
var vectorSearchResultList = resultsPage.Select(x => new VectorSearchResult<TRecord>((TRecord)x.record, x.score)).ToAsyncEnumerable();
318-
return new VectorSearchResults<TRecord>(vectorSearchResultList) { TotalCount = count };
316+
return Task.FromResult(new VectorSearchResults<TRecord>(vectorSearchResultList) { TotalCount = count });
319317
}
320318

321319
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBVectorStoreRecordCollection.cs

+2-9
Original file line numberDiff line numberDiff line change
@@ -253,20 +253,13 @@ await this._mongoCollection
253253
}
254254

255255
/// <inheritdoc />
256-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
256+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
257257
{
258258
Verify.NotNull(records);
259259

260260
var tasks = records.Select(record => this.UpsertAsync(record, cancellationToken));
261261
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
262-
263-
foreach (var result in results)
264-
{
265-
if (result is not null)
266-
{
267-
yield return (TKey)(object)result;
268-
}
269-
}
262+
return results.Where(r => r is not null).ToList();
270263
}
271264

272265
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeVectorStoreRecordCollection.cs

+3-6
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ await this.RunIndexOperationAsync(
303303
}
304304

305305
/// <inheritdoc />
306-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
306+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
307307
{
308308
Verify.NotNull(records);
309309

@@ -316,7 +316,7 @@ public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [E
316316

317317
if (vectors.Count == 0)
318318
{
319-
yield break;
319+
return [];
320320
}
321321

322322
Sdk.UpsertRequest request = new()
@@ -329,10 +329,7 @@ await this.RunIndexOperationAsync(
329329
"UpsertBatch",
330330
indexClient => indexClient.UpsertAsync(request, cancellationToken: cancellationToken)).ConfigureAwait(false);
331331

332-
foreach (var vector in vectors)
333-
{
334-
yield return (TKey)(object)vector.Id;
335-
}
332+
return vectors.Select(x => (TKey)(object)x.Id).ToList();
336333
}
337334

338335
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresVectorStoreRecordCollection.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public Task<TKey> UpsertAsync(TRecord record, CancellationToken cancellationToke
156156
}
157157

158158
/// <inheritdoc/>
159-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
159+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
160160
{
161161
Verify.NotNull(records);
162162

@@ -171,7 +171,7 @@ public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [E
171171

172172
if (storageModels.Count == 0)
173173
{
174-
yield break;
174+
return [];
175175
}
176176

177177
var keys = storageModels.Select(model => model[this._model.KeyProperty.StorageName]!).ToList();
@@ -180,7 +180,7 @@ await this.RunOperationAsync(OperationName, () =>
180180
this._client.UpsertBatchAsync(this.CollectionName, storageModels, this._model.KeyProperty.StorageName, cancellationToken)
181181
).ConfigureAwait(false);
182182

183-
foreach (var key in keys) { yield return (TKey)key!; }
183+
return keys.Select(key => (TKey)key!).ToList();
184184
}
185185

186186
/// <inheritdoc/>

dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantVectorStoreRecordCollection.cs

+8-22
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ await this.RunOperationAsync(
454454
}
455455

456456
/// <inheritdoc />
457-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
457+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
458458
{
459459
Verify.NotNull(records);
460460

@@ -471,28 +471,14 @@ await this.RunOperationAsync(
471471
UpsertName,
472472
() => this._qdrantClient.UpsertAsync(this._collectionName, pointStructs, true, cancellationToken: cancellationToken)).ConfigureAwait(false);
473473

474-
if (pointStructs.Count > 0)
475-
{
476-
switch (pointStructs[0].Id)
474+
return pointStructs.Count == 0
475+
? []
476+
: pointStructs[0].Id switch
477477
{
478-
case { HasNum: true }:
479-
foreach (var pointStruct in pointStructs)
480-
{
481-
yield return (TKey)(object)pointStruct.Id.Num;
482-
}
483-
break;
484-
485-
case { HasUuid: true }:
486-
foreach (var pointStruct in pointStructs)
487-
{
488-
yield return (TKey)(object)Guid.Parse(pointStruct.Id.Uuid);
489-
}
490-
break;
491-
492-
default:
493-
throw new UnreachableException("The Qdrant point ID is neither a number nor a UUID.");
494-
}
495-
}
478+
{ HasNum: true } => pointStructs.Select(pointStruct => (TKey)(object)pointStruct.Id.Num).ToList(),
479+
{ HasUuid: true } => pointStructs.Select(pointStruct => (TKey)(object)Guid.Parse(pointStruct.Id.Uuid)).ToList(),
480+
_ => throw new UnreachableException("The Qdrant point ID is neither a number nor a UUID.")
481+
};
496482
}
497483

498484
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.Redis/RedisHashSetVectorStoreRecordCollection.cs

+2-8
Original file line numberDiff line numberDiff line change
@@ -320,20 +320,14 @@ await this.RunOperationAsync(
320320
}
321321

322322
/// <inheritdoc />
323-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
323+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
324324
{
325325
Verify.NotNull(records);
326326

327327
// Upsert records in parallel.
328328
var tasks = records.Select(x => this.UpsertAsync(x, cancellationToken));
329329
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
330-
foreach (var result in results)
331-
{
332-
if (result is not null)
333-
{
334-
yield return (TKey)(object)result;
335-
}
336-
}
330+
return results.Where(r => r is not null).ToList();
337331
}
338332

339333
/// <inheritdoc />

dotnet/src/Connectors/Connectors.Memory.Redis/RedisJsonVectorStoreRecordCollection.cs

+2-6
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ await this.RunOperationAsync(
375375
}
376376

377377
/// <inheritdoc />
378-
public async IAsyncEnumerable<TKey> UpsertAsync(IEnumerable<TRecord> records, [EnumeratorCancellation] CancellationToken cancellationToken = default)
378+
public async Task<IReadOnlyList<TKey>> UpsertAsync(IEnumerable<TRecord> records, CancellationToken cancellationToken = default)
379379
{
380380
Verify.NotNull(records);
381381

@@ -407,11 +407,7 @@ await this.RunOperationAsync(
407407
.JSON()
408408
.MSetAsync(keyPathValues)).ConfigureAwait(false);
409409

410-
// Return keys of upserted records.
411-
foreach (var record in redisRecords)
412-
{
413-
yield return (TKey)(object)record.originalKey;
414-
}
410+
return redisRecords.Select(x => (TKey)(object)x.originalKey).ToList();
415411
}
416412

417413
/// <inheritdoc />

0 commit comments

Comments
 (0)