using AIStudio.Tools.Databases;
using AIStudio.Tools.Databases.VectorStore;
namespace AIStudio.Tests.Tools;
///
/// Keeps the points of one data source in memory, vectors included, for tests which index documents.
///
internal sealed class MemoryVectorStore() : VectorStoreClient("Test vectors in memory", string.Empty)
{
public Dictionary Points { get; } = new(StringComparer.Ordinal);
///
/// The points each call of RetrieveVectorsAsync asked for, in the order of the calls.
///
public List> RetrieveRequests { get; } = [];
///
/// Called with the points of every InsertEmbedding before they are kept, to look at the other store at that moment.
///
public Func, Task>? BeforeInsert { get; set; }
public override Task EnsureVectorStoreExists(string storeName, string dataSourceName, int vectorSize, CancellationToken token) => Task.FromResult(new VectorStoreEnsureResult(this.Points.Count == 0));
public override Task VectorStoreExists(string storeName, CancellationToken token) => Task.FromResult(true);
public override async Task InsertEmbedding(string storeName, IReadOnlyList points, CancellationToken token)
{
if (this.BeforeInsert is not null)
await this.BeforeInsert(points);
foreach (var point in points)
this.Points[point.PointId] = point;
}
public override Task> RetrieveVectorsAsync(string storeName, IReadOnlyList pointIds, CancellationToken token)
{
this.RetrieveRequests.Add(pointIds.ToList());
return Task.FromResult>(pointIds
.Where(this.Points.ContainsKey)
.Select(pointId => new StoredVector(pointId, this.Points[pointId].Vector))
.ToList());
}
public override Task DeleteEmbeddingByFile(string storeName, string filePath, string parentFileId, IReadOnlyCollection keepPointIds, CancellationToken token)
{
var deletedPointIds = this.Points.Values
.Where(point => (point.FilePath == filePath || point.ParentFileId == parentFileId) && !keepPointIds.Contains(point.PointId))
.Select(point => point.PointId)
.ToList();
foreach (var pointId in deletedPointIds)
this.Points.Remove(pointId);
return Task.CompletedTask;
}
public override Task DeleteVectorStore(string storeName, CancellationToken token)
{
this.Points.Clear();
return Task.CompletedTask;
}
public override Task OptimizeVectorStore(string storeName, CancellationToken token) => Task.CompletedTask;
public override Task RelocateEmbeddingFileAsync(string storeName, string parentFileId, string absolutePath, string relativePath, string fingerprint, CancellationToken token)
{
foreach (var point in this.Points.Values.Where(point => point.ParentFileId == parentFileId).ToList())
this.Points[point.PointId] = point with { AbsolutePath = absolutePath, RelativePath = relativePath, Fingerprint = fingerprint };
return Task.CompletedTask;
}
public override Task> SearchEmbeddingAsync(string storeName, IReadOnlyList vector, int maxMatches, IReadOnlyList hiddenChunks, CancellationToken token) => throw new NotSupportedException();
public override Task> SearchEmbeddingAsync(string storeName, IReadOnlyList vector, int maxMatches, VectorSearchFilter filter, IReadOnlyList hiddenChunks, CancellationToken token) => throw new NotSupportedException();
public override Task PrepareBackupAsync(CancellationToken token) => throw new NotSupportedException();
public override Task CopyStoreForBackupAsync(string backupId, string storeName, CancellationToken token) => throw new NotSupportedException();
public override async IAsyncEnumerable<(string Label, string Value)> GetDisplayInfo()
{
await Task.CompletedTask;
yield break;
}
public override void Dispose()
{
}
}