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
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ protected override void ProcessTypeProperties(Type type, VectorStoreCollectionDe

protected override bool IsKeyPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
{
supportedTypes = "string, Guid, ObjectId";
supportedTypes = "string, int, long, Guid, ObjectId";

return type == typeof(string) || type == typeof(Guid) || type == typeof(ObjectId);
return type == typeof(string) || type == typeof(int) || type == typeof(long) || type == typeof(Guid) || type == typeof(ObjectId);
}

protected override bool IsDataPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
Expand Down
12 changes: 9 additions & 3 deletions dotnet/src/VectorData/AzureAISearch/AzureAISearchCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ internal AzureAISearchCollection(SearchIndexClient searchIndexClient, string nam
Verify.NotNull(searchIndexClient);
Verify.NotNullOrWhiteSpace(name);

if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(object))
if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(Guid) && typeof(TKey) != typeof(object))
{
throw new NotSupportedException("Only string keys are supported.");
throw new NotSupportedException("Only string and Guid keys are supported.");
}

options ??= AzureAISearchCollectionOptions.Default;
Expand Down Expand Up @@ -791,7 +791,13 @@ private string GetStringKey(TKey key)
{
Verify.NotNull(key);

var stringKey = key as string ?? throw new UnreachableException("string key should have been validated during model building");
var stringKey = key switch
{
string s => s,
Guid g => g.ToString(),

_ => throw new UnreachableException("string key should have been validated during model building")
};

Verify.NotNullOrWhiteSpace(stringKey, nameof(key));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ protected override bool IsVectorPropertyTypeValid(Type type, [NotNullWhen(false)

internal static bool IsKeyPropertyTypeValidCore(Type type, [NotNullWhen(false)] out string? supportedTypes)
{
supportedTypes = "string";
supportedTypes = "string, Guid";

return type == typeof(string);
return type == typeof(string) || type == typeof(Guid);
}

internal static bool IsDataPropertyTypeValidCore(Type type, [NotNullWhen(false)] out string? supportedTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public class CosmosMongoCollection<TKey, TRecord> : VectorStoreCollection<TKey,
/// <summary>The size of the dynamic candidate list for search.</summary>
private readonly int _efSearch;

private static readonly Type[] s_validKeyTypes = [typeof(string), typeof(Guid), typeof(ObjectId), typeof(int), typeof(long)];

/// <summary>
/// Initializes a new instance of the <see cref="CosmosMongoCollection{TKey, TRecord}"/> class.
/// </summary>
Expand Down Expand Up @@ -95,9 +97,9 @@ internal CosmosMongoCollection(IMongoDatabase mongoDatabase, string name, Func<C
Verify.NotNull(mongoDatabase);
Verify.NotNullOrWhiteSpace(name);

if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(object))
if (!s_validKeyTypes.Contains(typeof(TKey)) && typeof(TKey) != typeof(object))
{
throw new NotSupportedException("Only string keys are supported.");
throw new NotSupportedException("Only ObjectID, string, Guid, int and long keys are supported.");
}

options ??= CosmosMongoCollectionOptions.Default;
Expand Down
16 changes: 14 additions & 2 deletions dotnet/src/VectorData/CosmosNoSql/CosmosNoSqlCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,12 @@ internal CosmosNoSqlCollection(
{
try
{
if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(CosmosNoSqlCompositeKey) && typeof(TKey) != typeof(object))
if (typeof(TKey) != typeof(string)
&& typeof(TKey) != typeof(Guid)
&& typeof(TKey) != typeof(CosmosNoSqlCompositeKey)
&& typeof(TKey) != typeof(object))
{
throw new NotSupportedException($"Only {nameof(String)} and {nameof(CosmosNoSqlCompositeKey)} keys are supported.");
throw new NotSupportedException($"Only string, Guid and {nameof(CosmosNoSqlCompositeKey)} keys are supported.");
}

this._database = databaseProvider(clientWrapper.Client);
Expand Down Expand Up @@ -852,13 +855,22 @@ private static IEnumerable<CosmosNoSqlCompositeKey> GetCompositeKeys(IEnumerable
=> keys switch
{
IEnumerable<CosmosNoSqlCompositeKey> k => k,

IEnumerable<string> k => k.Select(key => new CosmosNoSqlCompositeKey(recordKey: key, partitionKey: key)),

IEnumerable<Guid> k => k.Select(key =>
{
var guidString = key.ToString();
return new CosmosNoSqlCompositeKey(recordKey: guidString, partitionKey: guidString);
}),

IEnumerable<object> k => k.Select(key => key switch
{
string s => new CosmosNoSqlCompositeKey(recordKey: s, partitionKey: s),
CosmosNoSqlCompositeKey ck => ck,
_ => throw new ArgumentException($"Invalid key type '{key.GetType().Name}'.")
}),

_ => throw new UnreachableException()
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ internal class CosmosNoSqlModelBuilder() : CollectionJsonModelBuilder(s_modelBui

protected override bool IsKeyPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
{
// TODO: Cosmos supports other key types (int, Guid...)
supportedTypes = "string";
supportedTypes = "string, Guid";

return type == typeof(string);
return type == typeof(string) || type == typeof(Guid);
}

protected override bool IsDataPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
Expand Down
6 changes: 3 additions & 3 deletions dotnet/src/VectorData/MongoDB/MongoCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public class MongoCollection<TKey, TRecord> : VectorStoreCollection<TKey, TRecor
private readonly int? _numCandidates;

/// <summary>Types of keys permitted.</summary>
private readonly Type[] _validKeyTypes = [typeof(string), typeof(Guid), typeof(ObjectId)];
private static readonly Type[] s_validKeyTypes = [typeof(string), typeof(Guid), typeof(ObjectId), typeof(int), typeof(long)];

/// <summary>
/// Initializes a new instance of the <see cref="MongoCollection{TKey, TRecord}"/> class.
Expand Down Expand Up @@ -106,9 +106,9 @@ internal MongoCollection(IMongoDatabase mongoDatabase, string name, Func<MongoCo
Verify.NotNull(mongoDatabase);
Verify.NotNullOrWhiteSpace(name);

if (!this._validKeyTypes.Contains(typeof(TKey)) && typeof(TKey) != typeof(object))
if (!s_validKeyTypes.Contains(typeof(TKey)) && typeof(TKey) != typeof(object))
{
throw new NotSupportedException("Only string, Guid and ObjectID keys are supported.");
throw new NotSupportedException("Only ObjectID, string, Guid, int and long keys are supported.");
}

options ??= MongoCollectionOptions.Default;
Expand Down
12 changes: 9 additions & 3 deletions dotnet/src/VectorData/Pinecone/PineconeCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ internal PineconeCollection(PineconeClient pineconeClient, string name, Func<Pin
Verify.NotNull(pineconeClient);
VerifyCollectionName(name);

if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(object))
if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(Guid) && typeof(TKey) != typeof(object))
{
throw new NotSupportedException("Only string keys are supported.");
throw new NotSupportedException("Only string and Guid keys are supported.");
}

options ??= PineconeCollectionOptions.Default;
Expand Down Expand Up @@ -617,7 +617,13 @@ private string GetStringKey(TKey key)
{
Verify.NotNull(key);

var stringKey = key as string ?? throw new UnreachableException("string key should have been validated during model building");
var stringKey = key switch
{
string s => s,
Guid g => g.ToString(),

_ => throw new UnreachableException()
};

Verify.NotNullOrWhiteSpace(stringKey, nameof(key));

Expand Down
10 changes: 9 additions & 1 deletion dotnet/src/VectorData/Pinecone/PineconeFilterTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,21 @@ internal class PineconeFilterTranslator
private Extensions.VectorData.ProviderServices.CollectionModel _model = null!;
private ParameterExpression _recordParameter = null!;

internal Metadata Translate(LambdaExpression lambdaExpression, Extensions.VectorData.ProviderServices.CollectionModel model)
internal Metadata? Translate(LambdaExpression lambdaExpression, Extensions.VectorData.ProviderServices.CollectionModel model)
{
this._model = model;

Debug.Assert(lambdaExpression.Parameters.Count == 1);
this._recordParameter = lambdaExpression.Parameters[0];

// Pinecone doesn't seem to have a native way of expressing "always true" filters; since this scenario is important for fetching
// all records (via GetAsync with filter), we special-case and support it here. Note that false isn't supported (useless),
// nor is 'x && true'.
if (lambdaExpression.Body is ConstantExpression { Value: true })
{
return null;
}

var preprocessor = new FilterTranslationPreprocessor { SupportsParameterization = false };
var preprocessedExpression = preprocessor.Preprocess(lambdaExpression.Body);

Expand Down
15 changes: 13 additions & 2 deletions dotnet/src/VectorData/Pinecone/PineconeMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ public Vector MapFromDataToStorageModel(TRecord dataModel, Embedding<float>? gen
// TODO: what about sparse values?
var result = new Vector
{
Id = (string)keyObject,
Id = keyObject switch
{
string s => s,
Guid g => g.ToString(),
_ => throw new UnreachableException()
},
Values = values,
Metadata = metadata,
SparseValues = null
Expand All @@ -58,7 +63,13 @@ public TRecord MapFromStorageToDataModel(Vector storageModel, bool includeVector
{
var outputRecord = model.CreateRecord<TRecord>()!;

model.KeyProperty.SetValueAsObject(outputRecord, storageModel.Id);
model.KeyProperty.SetValueAsObject(outputRecord, model.KeyProperty.Type switch
{
var t when t == typeof(string) => storageModel.Id,
var t when t == typeof(Guid) => Guid.Parse(storageModel.Id),

_ => throw new UnreachableException()
});

if (includeVectors is true)
{
Expand Down
4 changes: 2 additions & 2 deletions dotnet/src/VectorData/Pinecone/PineconeModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ internal class PineconeModelBuilder() : CollectionModelBuilder(s_validationOptio

protected override bool IsKeyPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
{
supportedTypes = "string";
supportedTypes = "string, Guid";

return type == typeof(string);
return type == typeof(string) || type == typeof(Guid);
}

protected override bool IsDataPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
Expand Down
12 changes: 9 additions & 3 deletions dotnet/src/VectorData/Redis/RedisHashSetCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ internal RedisHashSetCollection(IDatabase database, string name, Func<RedisHashS
Verify.NotNull(database);
Verify.NotNullOrWhiteSpace(name);

if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(object))
if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(Guid) && typeof(TKey) != typeof(object))
{
throw new NotSupportedException("Only string keys are supported.");
throw new NotSupportedException("Only string and Guid keys are supported.");
}

options ??= RedisHashSetCollectionOptions.Default;
Expand Down Expand Up @@ -510,7 +510,13 @@ private string GetStringKey(TKey key)
{
Verify.NotNull(key);

var stringKey = key as string ?? throw new UnreachableException("string key should have been validated during model building");
var stringKey = key switch
{
string s => s,
Guid g => g.ToString(),

_ => throw new UnreachableException("string key should have been validated during model building")
};

Verify.NotNullOrWhiteSpace(stringKey, nameof(key));

Expand Down
20 changes: 17 additions & 3 deletions dotnet/src/VectorData/Redis/RedisHashSetMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Extensions.AI;
Expand All @@ -19,8 +20,13 @@ internal sealed class RedisHashSetMapper<TConsumerDataModel>(CollectionModel mod
/// <inheritdoc />
public (string Key, HashEntry[] HashEntries) MapFromDataToStorageModel(TConsumerDataModel dataModel, int recordIndex, IReadOnlyList<Embedding>?[]? generatedEmbeddings)
{
var keyValue = model.KeyProperty.GetValueAsObject(dataModel!) as string ??
throw new InvalidOperationException($"Missing key property {model.KeyProperty.ModelName} on provided record of type '{typeof(TConsumerDataModel).Name}'.");
var keyValue = model.KeyProperty.GetValueAsObject(dataModel!) switch
{
string s => s,
Guid g => g.ToString(),

_ => throw new InvalidOperationException($"Missing key property {model.KeyProperty.ModelName} on provided record of type '{typeof(TConsumerDataModel).Name}'.")
};

var hashEntries = new List<HashEntry>();
foreach (var property in model.DataProperties)
Expand Down Expand Up @@ -67,7 +73,15 @@ public TConsumerDataModel MapFromStorageToDataModel((string Key, HashEntry[] Has
var outputRecord = model.CreateRecord<TConsumerDataModel>()!;

// Set Key.
model.KeyProperty.SetValueAsObject(outputRecord, storageModel.Key);
model.KeyProperty.SetValueAsObject(outputRecord, model.KeyProperty.Type switch
{
Type t when t == typeof(string)
=> storageModel.Key,
Type t when t == typeof(Guid)
=> Guid.Parse(storageModel.Key),

_ => throw new UnreachableException()
});

// Set each vector property if embeddings should be returned.
if (includeVectors)
Expand Down
12 changes: 9 additions & 3 deletions dotnet/src/VectorData/Redis/RedisJsonCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ internal RedisJsonCollection(IDatabase database, string name, Func<RedisJsonColl
Verify.NotNull(database);
Verify.NotNullOrWhiteSpace(name);

if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(object))
if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(Guid) && typeof(TKey) != typeof(object))
{
throw new NotSupportedException("Only string keys are supported.");
throw new NotSupportedException("Only string or Guid keys are supported.");
}

var isDynamic = typeof(TRecord) == typeof(Dictionary<string, object?>);
Expand Down Expand Up @@ -596,7 +596,13 @@ private string GetStringKey(TKey key)
{
Verify.NotNull(key);

var stringKey = key as string ?? throw new UnreachableException("string key should have been validated during model building");
var stringKey = key switch
{
string s => s,
Guid g => g.ToString(),

_ => throw new UnreachableException("string key should have been validated during model building")
};

Verify.NotNullOrWhiteSpace(stringKey, nameof(key));

Expand Down
4 changes: 2 additions & 2 deletions dotnet/src/VectorData/Redis/RedisJsonModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ internal class RedisJsonModelBuilder(CollectionModelBuildingOptions options) : C

protected override bool IsKeyPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
{
supportedTypes = "string";
supportedTypes = "string, Guid";

return type == typeof(string);
return type == typeof(string) || type == typeof(Guid);
}

protected override bool IsDataPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
Expand Down
4 changes: 2 additions & 2 deletions dotnet/src/VectorData/Redis/RedisModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ internal class RedisModelBuilder(CollectionModelBuildingOptions options) : Colle

protected override bool IsKeyPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
{
supportedTypes = "string";
supportedTypes = "string, Guid";

return type == typeof(string);
return type == typeof(string) || type == typeof(Guid);
}

protected override bool IsDataPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
Expand Down
6 changes: 2 additions & 4 deletions dotnet/src/VectorData/SqlServer/SqlServerModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ internal class SqlServerModelBuilder() : CollectionModelBuilder(s_modelBuildingO

protected override bool IsKeyPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
{
supportedTypes = "int, long, string, Guid, DateTime, or byte[]";
supportedTypes = "int, long, string, Guid";

return type == typeof(int) // INT
|| type == typeof(long) // BIGINT
|| type == typeof(string) // VARCHAR
|| type == typeof(Guid) // UNIQUEIDENTIFIER
|| type == typeof(DateTime) // DATETIME2
|| type == typeof(byte[]); // VARBINARY
|| type == typeof(Guid); // UNIQUEIDENTIFIER
}

protected override bool IsDataPropertyTypeValid(Type type, [NotNullWhen(false)] out string? supportedTypes)
Expand Down
8 changes: 6 additions & 2 deletions dotnet/src/VectorData/SqliteVec/SqliteCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,13 @@ internal SqliteCollection(string connectionString, string name, Func<SqliteColle
Verify.NotNull(connectionString);
Verify.NotNullOrWhiteSpace(name);

if (typeof(TKey) != typeof(string) && typeof(TKey) != typeof(int) && typeof(TKey) != typeof(long) && typeof(TKey) != typeof(object))
if (typeof(TKey) != typeof(string)
&& typeof(TKey) != typeof(int)
&& typeof(TKey) != typeof(long)
&& typeof(TKey) != typeof(Guid)
&& typeof(TKey) != typeof(object))
{
throw new NotSupportedException("Only string, int and long keys are supported.");
throw new NotSupportedException("Only string, int, long and Guid keys are supported.");
}

options ??= SqliteCollectionOptions.Default;
Expand Down
Loading
Loading