209 lines
7.7 KiB
C#
209 lines
7.7 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Microsoft.Extensions.VectorData;
|
|
using Microsoft.Extensions.VectorData.ProviderServices;
|
|
using StackExchange.Redis;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.SemanticKernel.Connectors.Redis.UnitTests;
|
|
|
|
/// <summary>
|
|
/// Contains dynamic mapping tests for the <see cref="RedisHashSetMapper{TConsumerDataModel}"/> class.
|
|
/// </summary>
|
|
public class RedisHashSetDynamicMappingTests
|
|
{
|
|
private static readonly CollectionModel s_model = BuildModel(RedisHashSetMappingTestHelpers.s_definition);
|
|
|
|
private static readonly float[] s_floatVector = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
private static readonly double[] s_doubleVector = new double[] { 5.0d, 6.0d, 7.0d, 8.0d };
|
|
|
|
[Fact]
|
|
public void MapFromDataToStorageModelMapsAllSupportedTypes()
|
|
{
|
|
// Arrange.
|
|
var sut = new RedisHashSetMapper<Dictionary<string, object?>>(s_model);
|
|
var dataModel = new Dictionary<string, object?>
|
|
{
|
|
["Key"] = "key",
|
|
|
|
["StringData"] = "data 1",
|
|
["IntData"] = 1,
|
|
["UIntData"] = 2u,
|
|
["LongData"] = 3L,
|
|
["ULongData"] = 4ul,
|
|
["DoubleData"] = 5.5d,
|
|
["FloatData"] = 6.6f,
|
|
["NullableIntData"] = 7,
|
|
["NullableUIntData"] = 8u,
|
|
["NullableLongData"] = 9L,
|
|
["NullableULongData"] = 10ul,
|
|
["NullableDoubleData"] = 11.1d,
|
|
["NullableFloatData"] = 12.2f,
|
|
|
|
["FloatVector"] = new ReadOnlyMemory<float>(s_floatVector),
|
|
["DoubleVector"] = new ReadOnlyMemory<double>(s_doubleVector),
|
|
};
|
|
|
|
// Act.
|
|
var storageModel = sut.MapFromDataToStorageModel(dataModel, recordIndex: 0, generatedEmbeddings: null);
|
|
|
|
// Assert
|
|
Assert.Equal("key", storageModel.Key);
|
|
RedisHashSetMappingTestHelpers.VerifyHashSet(storageModel.HashEntries);
|
|
}
|
|
|
|
[Fact]
|
|
public void MapFromDataToStorageModelMapsNullValues()
|
|
{
|
|
// Arrange
|
|
CollectionModel model = BuildModel(new()
|
|
{
|
|
Properties =
|
|
[
|
|
new VectorStoreKeyProperty("Key", typeof(string)),
|
|
new VectorStoreDataProperty("StringData", typeof(string)) { StorageName = "storage_string_data" },
|
|
new VectorStoreDataProperty("NullableIntData", typeof(int?)),
|
|
new VectorStoreVectorProperty("FloatVector", typeof(ReadOnlyMemory<float>?), 10),
|
|
],
|
|
});
|
|
|
|
var dataModel = new Dictionary<string, object?>
|
|
{
|
|
["Key"] = "key",
|
|
["StringData"] = null,
|
|
["NullableIntData"] = null,
|
|
["FloatVector"] = null,
|
|
};
|
|
|
|
var sut = new RedisHashSetMapper<Dictionary<string, object?>>(model);
|
|
|
|
// Act
|
|
var storageModel = sut.MapFromDataToStorageModel(dataModel, recordIndex: 0, generatedEmbeddings: null);
|
|
|
|
// Assert
|
|
Assert.Equal("key", storageModel.Key);
|
|
|
|
Assert.Equal("storage_string_data", storageModel.HashEntries[0].Name.ToString());
|
|
Assert.True(storageModel.HashEntries[0].Value.IsNull);
|
|
|
|
Assert.Equal("NullableIntData", storageModel.HashEntries[1].Name.ToString());
|
|
Assert.True(storageModel.HashEntries[1].Value.IsNull);
|
|
}
|
|
|
|
[Fact]
|
|
public void MapFromStorageToDataModelMapsAllSupportedTypes()
|
|
{
|
|
// Arrange.
|
|
var hashSet = RedisHashSetMappingTestHelpers.CreateHashSet();
|
|
var sut = new RedisHashSetMapper<Dictionary<string, object?>>(s_model);
|
|
|
|
// Act.
|
|
var dataModel = sut.MapFromStorageToDataModel(("key", hashSet), includeVectors: true);
|
|
|
|
// Assert.
|
|
Assert.Equal("key", dataModel["Key"]);
|
|
Assert.Equal("data 1", dataModel["StringData"]);
|
|
Assert.Equal(1, dataModel["IntData"]);
|
|
Assert.Equal(2u, dataModel["UIntData"]);
|
|
Assert.Equal(3L, dataModel["LongData"]);
|
|
Assert.Equal(4ul, dataModel["ULongData"]);
|
|
Assert.Equal(5.5d, dataModel["DoubleData"]);
|
|
Assert.Equal(6.6f, dataModel["FloatData"]);
|
|
Assert.Equal(7, dataModel["NullableIntData"]);
|
|
Assert.Equal(8u, dataModel["NullableUIntData"]);
|
|
Assert.Equal(9L, dataModel["NullableLongData"]);
|
|
Assert.Equal(10ul, dataModel["NullableULongData"]);
|
|
Assert.Equal(11.1d, dataModel["NullableDoubleData"]);
|
|
Assert.Equal(12.2f, dataModel["NullableFloatData"]);
|
|
Assert.Equal(new float[] { 1, 2, 3, 4 }, ((ReadOnlyMemory<float>)dataModel["FloatVector"]!).ToArray());
|
|
Assert.Equal(new double[] { 5, 6, 7, 8 }, ((ReadOnlyMemory<double>)dataModel["DoubleVector"]!).ToArray());
|
|
}
|
|
|
|
[Fact]
|
|
public void MapFromStorageToDataModelMapsNullValues()
|
|
{
|
|
// Arrange
|
|
var model = BuildModel(new()
|
|
{
|
|
Properties =
|
|
[
|
|
new VectorStoreKeyProperty("Key", typeof(string)),
|
|
new VectorStoreDataProperty("StringData", typeof(string)) { StorageName = "storage_string_data" },
|
|
new VectorStoreDataProperty("NullableIntData", typeof(int?)),
|
|
new VectorStoreVectorProperty("FloatVector", typeof(ReadOnlyMemory<float>?), 10),
|
|
]
|
|
});
|
|
|
|
var hashSet = new HashEntry[]
|
|
{
|
|
new("storage_string_data", RedisValue.Null),
|
|
new("NullableIntData", RedisValue.Null),
|
|
new("FloatVector", RedisValue.Null),
|
|
};
|
|
|
|
var sut = new RedisHashSetMapper<Dictionary<string, object?>>(model);
|
|
|
|
// Act
|
|
var dataModel = sut.MapFromStorageToDataModel(("key", hashSet), includeVectors: true);
|
|
|
|
// Assert
|
|
Assert.Equal("key", dataModel["Key"]);
|
|
Assert.Null(dataModel["StringData"]);
|
|
Assert.Null(dataModel["NullableIntData"]);
|
|
Assert.Null(dataModel["FloatVector"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void MapFromDataToStorageModelSkipsMissingProperties()
|
|
{
|
|
// Arrange.
|
|
var model = BuildModel(new()
|
|
{
|
|
Properties =
|
|
[
|
|
new VectorStoreKeyProperty("Key", typeof(string)),
|
|
new VectorStoreDataProperty("StringData", typeof(string)) { StorageName = "storage_string_data" },
|
|
new VectorStoreDataProperty("NullableIntData", typeof(int?)),
|
|
new VectorStoreVectorProperty("FloatVector", typeof(ReadOnlyMemory<float>?), 10),
|
|
]
|
|
});
|
|
|
|
var sut = new RedisHashSetMapper<Dictionary<string, object?>>(model);
|
|
var dataModel = new Dictionary<string, object?> { ["Key"] = "key" };
|
|
|
|
// Act.
|
|
var storageModel = sut.MapFromDataToStorageModel(dataModel, recordIndex: 0, generatedEmbeddings: null);
|
|
|
|
// Assert
|
|
Assert.Equal("key", storageModel.Key);
|
|
|
|
Assert.Equal("storage_string_data", storageModel.HashEntries[0].Name.ToString());
|
|
Assert.True(storageModel.HashEntries[0].Value.IsNull);
|
|
|
|
Assert.Equal("NullableIntData", storageModel.HashEntries[1].Name.ToString());
|
|
Assert.True(storageModel.HashEntries[1].Value.IsNull);
|
|
}
|
|
|
|
[Fact]
|
|
public void MapFromStorageToDataModelSkipsMissingProperties()
|
|
{
|
|
// Arrange.
|
|
var hashSet = Array.Empty<HashEntry>();
|
|
|
|
var sut = new RedisHashSetMapper<Dictionary<string, object?>>(s_model);
|
|
|
|
// Act.
|
|
var dataModel = sut.MapFromStorageToDataModel(("key", hashSet), includeVectors: true);
|
|
|
|
// Assert.
|
|
Assert.Single(dataModel);
|
|
Assert.Equal("key", dataModel["Key"]);
|
|
}
|
|
|
|
private static CollectionModel BuildModel(VectorStoreCollectionDefinition definition)
|
|
=> new RedisModelBuilder(RedisHashSetCollection<object, Dictionary<string, object?>>.ModelBuildingOptions)
|
|
.BuildDynamic(definition, defaultEmbeddingGenerator: null);
|
|
}
|