|
3 | 3 | using System;
|
4 | 4 | using System.Collections.Generic;
|
5 | 5 | using System.Linq;
|
6 |
| -using System.Text.Json; |
7 |
| -using System.Text.Json.Nodes; |
8 | 6 | using Microsoft.SemanticKernel.Data;
|
9 | 7 | using Pinecone;
|
10 | 8 |
|
@@ -61,6 +59,7 @@ public PineconeVectorStoreRecordMapper(
|
61 | 59 | VectorStoreRecordPropertyReader propertyReader)
|
62 | 60 | {
|
63 | 61 | // Validate property types.
|
| 62 | + propertyReader.VerifyHasParameterlessConstructor(); |
64 | 63 | propertyReader.VerifyKeyProperties(s_supportedKeyTypes);
|
65 | 64 | propertyReader.VerifyDataProperties(s_supportedDataTypes, s_supportedEnumerableDataElementTypes);
|
66 | 65 | propertyReader.VerifyVectorProperties(s_supportedVectorTypes);
|
@@ -110,52 +109,70 @@ public Vector MapFromDataToStorageModel(TRecord dataModel)
|
110 | 109 | /// <inheritdoc />
|
111 | 110 | public TRecord MapFromStorageToDataModel(Vector storageModel, StorageToDataModelMapperOptions options)
|
112 | 111 | {
|
113 |
| - var keyJsonName = this._propertyReader.KeyPropertyJsonName; |
114 |
| - var outputJsonObject = new JsonObject |
115 |
| - { |
116 |
| - { keyJsonName, JsonValue.Create(storageModel.Id) }, |
117 |
| - }; |
| 112 | + // Construct the output record. |
| 113 | + var outputRecord = (TRecord)this._propertyReader.ParameterLessConstructorInfo.Invoke(null); |
118 | 114 |
|
| 115 | + // Set Key. |
| 116 | + this._propertyReader.KeyPropertyInfo.SetValue(outputRecord, storageModel.Id); |
| 117 | + |
| 118 | + // Set Vector. |
119 | 119 | if (options?.IncludeVectors is true)
|
120 | 120 | {
|
121 |
| - var propertyName = this._propertyReader.GetStoragePropertyName(this._propertyReader.FirstVectorPropertyName!); |
122 |
| - var jsonName = this._propertyReader.GetJsonPropertyName(this._propertyReader.FirstVectorPropertyName!); |
123 |
| - outputJsonObject.Add(jsonName, new JsonArray(storageModel.Values.Select(x => JsonValue.Create(x)).ToArray())); |
| 121 | + this._propertyReader.FirstVectorPropertyInfo!.SetValue( |
| 122 | + outputRecord, |
| 123 | + new ReadOnlyMemory<float>(storageModel.Values)); |
124 | 124 | }
|
125 | 125 |
|
| 126 | + // Set Data. |
126 | 127 | if (storageModel.Metadata != null)
|
127 | 128 | {
|
128 |
| - foreach (var dataProperty in this._propertyReader.DataPropertiesInfo) |
129 |
| - { |
130 |
| - var propertyName = this._propertyReader.GetStoragePropertyName(dataProperty.Name); |
131 |
| - var jsonName = this._propertyReader.GetJsonPropertyName(dataProperty.Name); |
132 |
| - |
133 |
| - if (storageModel.Metadata.TryGetValue(propertyName, out var value)) |
134 |
| - { |
135 |
| - outputJsonObject.Add(jsonName, ConvertFromMetadataValueToJsonNode(value)); |
136 |
| - } |
137 |
| - } |
| 129 | + VectorStoreRecordMapping.SetValuesOnProperties( |
| 130 | + outputRecord, |
| 131 | + this._propertyReader.DataPropertiesInfo, |
| 132 | + this._propertyReader.StoragePropertyNamesMap, |
| 133 | + storageModel.Metadata, |
| 134 | + ConvertFromMetadataValueToNativeType); |
138 | 135 | }
|
139 | 136 |
|
140 |
| - return outputJsonObject.Deserialize<TRecord>()!; |
| 137 | + return outputRecord; |
141 | 138 | }
|
142 | 139 |
|
143 |
| - private static JsonNode? ConvertFromMetadataValueToJsonNode(MetadataValue metadataValue) |
| 140 | + private static object? ConvertFromMetadataValueToNativeType(MetadataValue metadataValue, Type targetType) |
144 | 141 | => metadataValue.Inner switch
|
145 | 142 | {
|
146 | 143 | null => null,
|
147 |
| - bool boolValue => JsonValue.Create(boolValue), |
148 |
| - string stringValue => JsonValue.Create(stringValue), |
149 |
| - int intValue => JsonValue.Create(intValue), |
150 |
| - long longValue => JsonValue.Create(longValue), |
151 |
| - float floatValue => JsonValue.Create(floatValue), |
152 |
| - double doubleValue => JsonValue.Create(doubleValue), |
153 |
| - decimal decimalValue => JsonValue.Create(decimalValue), |
154 |
| - MetadataValue[] array => new JsonArray(array.Select(ConvertFromMetadataValueToJsonNode).ToArray()), |
155 |
| - List<MetadataValue> list => new JsonArray(list.Select(ConvertFromMetadataValueToJsonNode).ToArray()), |
| 144 | + bool boolValue => boolValue, |
| 145 | + string stringValue => stringValue, |
| 146 | + // Numeric values are not always coming from the SDK in the desired type |
| 147 | + // that the data model requires, so we need to convert them. |
| 148 | + int intValue => ConvertToNumericValue(intValue, targetType), |
| 149 | + long longValue => ConvertToNumericValue(longValue, targetType), |
| 150 | + float floatValue => ConvertToNumericValue(floatValue, targetType), |
| 151 | + double doubleValue => ConvertToNumericValue(doubleValue, targetType), |
| 152 | + decimal decimalValue => ConvertToNumericValue(decimalValue, targetType), |
| 153 | + MetadataValue[] array => VectorStoreRecordMapping.CreateEnumerable(array.Select(x => ConvertFromMetadataValueToNativeType(x, VectorStoreRecordPropertyVerification.GetCollectionElementType(targetType))), targetType), |
| 154 | + List<MetadataValue> list => VectorStoreRecordMapping.CreateEnumerable(list.Select(x => ConvertFromMetadataValueToNativeType(x, VectorStoreRecordPropertyVerification.GetCollectionElementType(targetType))), targetType), |
156 | 155 | _ => throw new VectorStoreRecordMappingException($"Unsupported metadata type: '{metadataValue.Inner?.GetType().FullName}'."),
|
157 | 156 | };
|
158 | 157 |
|
| 158 | + private static object? ConvertToNumericValue(object? number, Type targetType) |
| 159 | + { |
| 160 | + if (number is null) |
| 161 | + { |
| 162 | + return null; |
| 163 | + } |
| 164 | + |
| 165 | + return targetType switch |
| 166 | + { |
| 167 | + Type intType when intType == typeof(int) || intType == typeof(int?) => Convert.ToInt32(number), |
| 168 | + Type longType when longType == typeof(long) || longType == typeof(long?) => Convert.ToInt64(number), |
| 169 | + Type floatType when floatType == typeof(float) || floatType == typeof(float?) => Convert.ToSingle(number), |
| 170 | + Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?) => Convert.ToDouble(number), |
| 171 | + Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?) => Convert.ToDecimal(number), |
| 172 | + _ => throw new VectorStoreRecordMappingException($"Unsupported target numeric type '{targetType.FullName}'."), |
| 173 | + }; |
| 174 | + } |
| 175 | + |
159 | 176 | // TODO: take advantage of MetadataValue.TryCreate once we upgrade the version of Pinecone.NET
|
160 | 177 | private static MetadataValue ConvertToMetadataValue(object? sourceValue)
|
161 | 178 | => sourceValue switch
|
|
0 commit comments