Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 12 additions & 0 deletions dotnet/src/VectorData/Redis/RedisJsonMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ internal sealed class RedisJsonMapper<TConsumerDataModel>(
/// <summary>The key property.</summary>
private readonly string _keyPropertyStorageName = model.KeyProperty.StorageName;

/// <summary>Storage names for the allowed properties that should be retained in the Redis payload.</summary>
private readonly HashSet<string> _allowedStorageNames = new(
model.DataProperties.Select(p => p.StorageName).Concat(model.VectorProperties.Select(p => p.StorageName)),
StringComparer.Ordinal);

/// <inheritdoc />
public (string Key, JsonNode Node) MapFromDataToStorageModel(TConsumerDataModel dataModel, int recordIndex, IReadOnlyList<Embedding>?[]? generatedEmbeddings)
{
Expand All @@ -41,6 +46,13 @@ internal sealed class RedisJsonMapper<TConsumerDataModel>(
var keyValue = jsonValue.ToString();
jsonNode.Remove(this._keyPropertyStorageName);

// Remove any properties that are not part of the data model.
var propertiesToRemove = jsonNode.Select(x => x.Key).Where(key => !this._allowedStorageNames.Contains(key)).ToList();
foreach (var keyToRemove in propertiesToRemove)
{
jsonNode.Remove(keyToRemove);
}
Comment thread
summitbaj marked this conversation as resolved.

// Go over the vector properties; inject any generated embeddings to overwrite the JSON serialized above.
// Also, for Embedding<T> properties we also need to overwrite with a simple array (since Embedding<T> gets serialized as a complex object).
for (var i = 0; i < model.VectorProperties.Count; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,10 @@ public async Task CanDeleteManyRecordsWithVectorsAsync(bool useDefinition)
}

[Theory]
[InlineData(true, true, """{"data1_json_name":"data 1","data2":"data 2","vector1_json_name":[1,2,3,4],"vector2":[1,2,3,4],"notAnnotated":null}""")]
[InlineData(true, false, """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4],"NotAnnotated":null}""")]
[InlineData(false, true, """{"data1_json_name":"data 1","data2":"data 2","vector1_json_name":[1,2,3,4],"vector2":[1,2,3,4],"notAnnotated":null}""")]
[InlineData(false, false, """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4],"NotAnnotated":null}""")]
[InlineData(true, true, """{"data1_json_name":"data 1","data2":"data 2","vector1_json_name":[1,2,3,4],"vector2":[1,2,3,4]}""")]
[InlineData(true, false, """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4]}""")]
[InlineData(false, true, """{"data1_json_name":"data 1","data2":"data 2","vector1_json_name":[1,2,3,4],"vector2":[1,2,3,4]}""")]
[InlineData(false, false, """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4]}""")]
Comment on lines +308 to +311
public async Task CanUpsertRecordAsync(bool useDefinition, bool useCustomJsonSerializerOptions, string expectedUpsertedJson)
{
// Arrange
Expand All @@ -320,7 +320,7 @@ public async Task CanUpsertRecordAsync(bool useDefinition, bool useCustomJsonSer
await sut.UpsertAsync(model);

// Assert
// TODO: Fix issue where NotAnnotated is being included in the JSON.
// (Fixed) Removed TODO regarding NotAnnotated being included in the JSON.
Comment thread
summitbaj marked this conversation as resolved.
Outdated
var expectedArgs = new object[] { TestRecordKey1, "$", expectedUpsertedJson };
this._redisDatabaseMock
.Verify(
Expand All @@ -346,8 +346,8 @@ public async Task CanUpsertManyRecordsAsync(bool useDefinition)
await sut.UpsertAsync([model1, model2]);

// Assert
// TODO: Fix issue where NotAnnotated is being included in the JSON.
var expectedArgs = new object[] { TestRecordKey1, "$", """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4],"NotAnnotated":null}""", TestRecordKey2, "$", """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4],"NotAnnotated":null}""" };
// (Fixed) Removed TODO regarding NotAnnotated being included in the JSON.
var expectedArgs = new object[] { TestRecordKey1, "$", """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4]}""", TestRecordKey2, "$", """{"data1_json_name":"data 1","Data2":"data 2","vector1_json_name":[1,2,3,4],"Vector2":[1,2,3,4]}""" };
this._redisDatabaseMock
.Verify(
x => x.ExecuteAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public void MapsAllFieldsFromDataToStorageModel()
Assert.Equal("data 2", jsonObject?["Data2"]?.ToString());
Assert.Equal(new float[] { 1, 2, 3, 4 }, jsonObject?["Vector1"]?.AsArray().GetValues<float>().ToArray());
Assert.Equal(new float[] { 5, 6, 7, 8 }, jsonObject?["Vector2"]?.AsArray().GetValues<float>().ToArray());
Assert.False(jsonObject!.ContainsKey("NotAnnotated"), "Unannotated properties should not be included in the storage model.");
Comment thread
summitbaj marked this conversation as resolved.
Outdated
}

[Fact]
Expand All @@ -56,6 +57,7 @@ public void MapsAllFieldsFromDataToStorageModelWithCustomSerializerOptions()
Assert.Equal("data 2", jsonObject?["data2"]?.ToString());
Assert.Equal(new float[] { 1, 2, 3, 4 }, jsonObject?["vector1"]?.AsArray().GetValues<float>().ToArray());
Assert.Equal(new float[] { 5, 6, 7, 8 }, jsonObject?["vector2"]?.AsArray().GetValues<float>().ToArray());
Assert.False(jsonObject!.ContainsKey("notAnnotated"), "Unannotated properties should not be included in the storage model.");
}

[Fact]
Expand Down
Loading