Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ FodyWeavers.xsd
*.iml
*.iws

# VS Code
.vscode/

.env
certs/
launchSettings.json
Expand Down
10 changes: 9 additions & 1 deletion dotnet/src/VectorData/CosmosNoSql/CosmosNoSqlCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ await this._database
/// <inheritdoc />
public override async Task<TRecord?> GetAsync(TKey key, RecordRetrievalOptions? options = null, CancellationToken cancellationToken = default)
{
Verify.NotNull(key);

return await this.GetAsync([key], options, cancellationToken)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
Expand All @@ -343,11 +345,17 @@ public override async IAsyncEnumerable<TRecord> GetAsync(
throw new NotSupportedException(VectorDataStrings.IncludeVectorsNotSupportedWithEmbeddingGeneration);
}

var compositeKeys = GetCompositeKeys(keys).ToList();
if (compositeKeys.Count == 0)
{
yield break;
}

var queryDefinition = CosmosNoSqlCollectionQueryBuilder.BuildSelectQuery(
this._model,
this._model.KeyProperty.StorageName,
this._partitionKeyProperty.StorageName,
GetCompositeKeys(keys).ToList(),
compositeKeys,
includeVectors);

await foreach (var jsonObject in this.GetItemsAsync<JsonObject>(queryDefinition, OperationName, cancellationToken).ConfigureAwait(false))
Expand Down
10 changes: 10 additions & 0 deletions dotnet/src/VectorData/Redis/RedisJsonCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ public override async IAsyncEnumerable<TRecord> GetAsync(IEnumerable<TKey> keys,
};
#pragma warning restore CA1851 // Possible multiple enumerations of 'IEnumerable' collection

if (keysList.Count == 0)
{
yield break;
}

// Create Options
var maybePrefixedKeys = keysList.Select(key => this.PrefixKeyIfNeeded(key));
var redisKeys = maybePrefixedKeys.Select(x => new RedisKey(x)).ToArray();
Expand Down Expand Up @@ -392,6 +397,11 @@ public override async Task UpsertAsync(IEnumerable<TRecord> records, Cancellatio
redisRecords.Add((maybePrefixedKey, redisJsonRecord.Key, redisJsonRecord.SerializedRecord));
}

if (redisRecords.Count == 0)
{
return;
}

// Upsert.
var keyPathValues = redisRecords.Select(x => new KeyPathValue(x.maybePrefixedKey, "$", x.serializedRecord)).ToArray();
await this.RunOperationAsync(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) Microsoft. All rights reserved.

using AzureAISearch.ConformanceTests.Support;
using Microsoft.Extensions.VectorData;
using VectorData.ConformanceTests.Xunit;
using Xunit;

namespace AzureAISearch.ConformanceTests;

public class AzureAISearchAllSupportedTypesTests(AzureAISearchFixture fixture) : IClassFixture<AzureAISearchFixture>
{
[ConditionalFact]
public async Task AllTypesBatchGetAsync()
{
var collection = fixture.TestStore.DefaultVectorStore.GetCollection<string, AzureAISearchAllTypes>("all-types", AzureAISearchAllTypes.GetRecordDefinition());
await collection.EnsureCollectionExistsAsync();

List<AzureAISearchAllTypes> records =
[
new()
{
Id = "all-types-1",
BoolProperty = true,
NullableBoolProperty = false,
StringProperty = "string prop 1",
NullableStringProperty = "nullable prop 1",
IntProperty = 1,
NullableIntProperty = 10,
LongProperty = 100L,
NullableLongProperty = 1000L,
FloatProperty = 10.5f,
NullableFloatProperty = 100.5f,
DoubleProperty = 23.75d,
NullableDoubleProperty = 233.75d,
DateTimeOffsetProperty = DateTimeOffset.UtcNow,
NullableDateTimeOffsetProperty = DateTimeOffset.UtcNow,
StringArray = ["one", "two"],
StringList = ["eleven", "twelve"],
BoolArray = [true, false],
BoolList = [true, false],
IntArray = [1, 2],
IntList = [11, 12],
LongArray = [100L, 200L],
LongList = [1100L, 1200L],
FloatArray = [1.5f, 2.5f],
FloatList = [11.5f, 12.5f],
DoubleArray = [1.5d, 2.5d],
DoubleList = [11.5d, 12.5d],
DateTimeOffsetArray = [DateTimeOffset.UtcNow, DateTimeOffset.UtcNow],
DateTimeOffsetList = [DateTimeOffset.UtcNow, DateTimeOffset.UtcNow],
Embedding = new ReadOnlyMemory<float>([1.5f, 2.5f, 3.5f, 4.5f, 5.5f, 6.5f, 7.5f, 8.5f])
},
new()
{
Id = "all-types-2",
BoolProperty = false,
NullableBoolProperty = null,
StringProperty = "string prop 2",
NullableStringProperty = null,
IntProperty = 2,
NullableIntProperty = null,
LongProperty = 200L,
NullableLongProperty = null,
FloatProperty = 20.5f,
NullableFloatProperty = null,
DoubleProperty = 43.75,
NullableDoubleProperty = null,
Embedding = ReadOnlyMemory<float>.Empty,
// From https://learn.microsoft.com/en-us/rest/api/searchservice/supported-data-types:
// "All of the above types are nullable, except for collections of primitive and complex types, for example, Collection(Edm.String)"
// So for collections, we can't use nulls.
StringArray = [],
StringList = [],
BoolArray = [],
BoolList = [],
IntArray = [],
IntList = [],
LongArray = [],
LongList = [],
FloatArray = [],
FloatList = [],
DoubleArray = [],
DoubleList = [],
DateTimeOffsetArray = [],
DateTimeOffsetList = [],
}
];

try
{
await collection.UpsertAsync(records);

var allTypes = await collection.GetAsync(records.Select(r => r.Id), new RecordRetrievalOptions { IncludeVectors = true }).ToListAsync();

var allTypes1 = allTypes.Single(x => x.Id == records[0].Id);
var allTypes2 = allTypes.Single(x => x.Id == records[1].Id);

records[0].AssertEqual(allTypes1);
records[1].AssertEqual(allTypes2);
}
finally
{
await collection.EnsureCollectionDeletedAsync();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.

using AzureAISearch.ConformanceTests.Support;
using VectorData.ConformanceTests;
using Xunit;

namespace AzureAISearch.ConformanceTests;

public class AzureAISearchCollectionManagementTests(AzureAISearchFixture fixture)
: CollectionManagementTests<string>(fixture), IClassFixture<AzureAISearchFixture>
{
// Azure AI search only supports lowercase letters, digits or dashes.
public override string CollectionName => "collection-tests";
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.

using AzureAISearch.ConformanceTests.Support;
using VectorData.ConformanceTests.Filter;
using VectorData.ConformanceTests;
using VectorData.ConformanceTests.Support;
using Xunit;

namespace AzureAISearch.ConformanceTests.Filter;
namespace AzureAISearch.ConformanceTests;

public class AzureAISearchBasicFilterTests(AzureAISearchBasicFilterTests.Fixture fixture)
: BasicFilterTests<string>(fixture), IClassFixture<AzureAISearchBasicFilterTests.Fixture>
public class AzureAISearchFilterTests(AzureAISearchFilterTests.Fixture fixture)
: FilterTests<string>(fixture), IClassFixture<AzureAISearchFilterTests.Fixture>
{
// Azure AI Search only supports search.in() over strings
public override Task Contains_over_inline_int_array()
=> Assert.ThrowsAsync<NotSupportedException>(() => base.Contains_over_inline_int_array());

public new class Fixture : BasicFilterTests<string>.Fixture
public new class Fixture : FilterTests<string>.Fixture
{
public override TestStore TestStore => AzureAISearchTestStore.Instance;

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.

using AzureAISearch.ConformanceTests.Support;
using VectorData.ConformanceTests.ModelTests;
using VectorData.ConformanceTests.Support;
using Xunit;

namespace AzureAISearch.ConformanceTests.ModelTests;

public class AzureAISearchBasicModelTests(AzureAISearchBasicModelTests.Fixture fixture)
: BasicModelTests<string>(fixture), IClassFixture<AzureAISearchBasicModelTests.Fixture>
{
public new class Fixture : BasicModelTests<string>.Fixture
{
public override string CollectionName => "basic-" + AzureAISearchTestEnvironment.TestIndexPostfix;

public override TestStore TestStore => AzureAISearchTestStore.Instance;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.

using AzureAISearch.ConformanceTests.Support;
using VectorData.ConformanceTests.ModelTests;
using VectorData.ConformanceTests.Support;
using Xunit;

namespace AzureAISearch.ConformanceTests.ModelTests;

public class AzureAISearchDynamicModelTests(AzureAISearchDynamicModelTests.Fixture fixture)
: DynamicModelTests<string>(fixture), IClassFixture<AzureAISearchDynamicModelTests.Fixture>
{
public new class Fixture : DynamicModelTests<string>.Fixture
{
public override string CollectionName => "dynamic-" + AzureAISearchTestEnvironment.TestIndexPostfix;

public override TestStore TestStore => AzureAISearchTestStore.Instance;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.

using AzureAISearch.ConformanceTests.Support;
using VectorData.ConformanceTests.ModelTests;
using VectorData.ConformanceTests.Support;
using Xunit;

namespace AzureAISearch.ConformanceTests.ModelTests;

public class AzureAISearchNoDataModelTests(AzureAISearchNoDataModelTests.Fixture fixture)
: NoDataModelTests<string>(fixture), IClassFixture<AzureAISearchNoDataModelTests.Fixture>
{
public new class Fixture : NoDataModelTests<string>.Fixture
{
public override string CollectionName => "nodata-" + AzureAISearchTestEnvironment.TestIndexPostfix;

public override TestStore TestStore => AzureAISearchTestStore.Instance;
}
}
Loading
Loading