Skip to content

Commit

Permalink
Some tidying up (#20)
Browse files Browse the repository at this point in the history
This commit 

- Moves the implicit conversions for Grpc types to Qdrant.Client.Grpc. 
- Introduce a conversion for Values and update usage in tests
- Mark timeout readonly and simplify switch not null check
- Add implicit conversions for WithPayloadSelector and WithVectorsSelector.
  • Loading branch information
russcam authored Oct 28, 2023
1 parent 629beb5 commit 0b3bbb6
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 64 deletions.
4 changes: 2 additions & 2 deletions examples/Examples/Points.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public async Task Upsert()
new PointStruct
{
Id = 1,
Vectors = new Vectors { Vector = new []{ 1, 2, 3, 4 } },
Vectors = new [] { 1f, 2f, 3f, 4f },
Payload =
{
["color"] = "blue",
Expand All @@ -34,7 +34,7 @@ public async Task Upsert()
new PointStruct
{
Id = 2,
Vectors = new Vectors { Vector = new[] { 2, 3, 4, 5 } },
Vectors = new[] { 2f, 3f, 4f, 5f },
Payload =
{
["color"] = "red",
Expand Down
File renamed without changes.
14 changes: 14 additions & 0 deletions src/Qdrant.Client/Grpc/Vector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Qdrant.Client.Grpc;

/// <summary>
/// A vector
/// </summary>
public partial class Vector
{
/// <summary>
/// Implicitly converts an array of <see cref="float"/> to a new instance of <see cref="Vector"/>
/// </summary>
/// <param name="values">the array of floats</param>
/// <returns>a new instance of <see cref="Vector"/></returns>
public static implicit operator Vector(float[] values) => new() { Data = { values } };
}
30 changes: 30 additions & 0 deletions src/Qdrant.Client/Grpc/Vectors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace Qdrant.Client.Grpc;

/// <summary>
/// A single vector or map of named vectors.
/// </summary>
public partial class Vectors
{
/// <summary>
/// Implicitly converts an array of <see cref="float"/> to a new instance of <see cref="Vectors"/>
/// </summary>
/// <param name="values">the array of floats</param>
/// <returns>a new instance of <see cref="Vectors"/></returns>
public static implicit operator Vectors(float[] values) =>
new() { Vector = new() { Data = { values } } };

/// <summary>
/// Implicitly converts a dictionary of <see cref="string"/> and array of <see cref="float"/> to a new instance
/// of <see cref="Vectors"/>
/// </summary>
/// <param name="values">a dictionary of string and array of floats</param>
/// <returns>a new instance of <see cref="Vectors"/></returns>
public static implicit operator Vectors(Dictionary<string, float[]> values)
{
var namedVectors = new NamedVectors();
foreach (var value in values)
namedVectors.Vectors.Add(value.Key, value.Value);

return new Vectors { Vectors_ = namedVectors };
}
}
14 changes: 14 additions & 0 deletions src/Qdrant.Client/Grpc/WithPayloadSelector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Qdrant.Client.Grpc;

/// <summary>
/// Selects payload to return
/// </summary>
public partial class WithPayloadSelector
{
/// <summary>
/// Implicitly converts <see cref="bool"/> to a new instance of <see cref="WithPayloadSelector"/>
/// </summary>
/// <param name="enable">If <code>true</code> return all payload, if <code>false</code> then none</param>
/// <returns>a new instance of <see cref="WithPayloadSelector"/></returns>
public static implicit operator WithPayloadSelector(bool enable) => new() { Enable = enable };
}
14 changes: 14 additions & 0 deletions src/Qdrant.Client/Grpc/WithVectorsSelector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Qdrant.Client.Grpc;

/// <summary>
/// Selects vectors to return
/// </summary>
public partial class WithVectorsSelector
{
/// <summary>
/// Implicitly converts <see cref="bool"/> to a new instance of <see cref="WithPayloadSelector"/>
/// </summary>
/// <param name="enable">If <code>true</code> return all vectors, if <code>false</code> then none</param>
/// <returns>a new instance of <see cref="WithPayloadSelector"/></returns>
public static implicit operator WithVectorsSelector(bool enable) => new() { Enable = enable };
}
13 changes: 7 additions & 6 deletions src/Qdrant.Client/QdrantClient.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System.Runtime.InteropServices;
using Google.Protobuf.Collections;
using Grpc.Core;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Qdrant.Client.Grpc;

namespace Qdrant.Client;

// ReSharper disable UnusedMethodReturnValue.Global
// ReSharper disable UnusedMember.Global

/// <summary>
/// Client for the Qdrant vector database.
Expand All @@ -22,7 +22,7 @@ public class QdrantClient : IDisposable
private readonly Points.PointsClient _pointsClient;
private readonly Snapshots.SnapshotsClient _snapshotsClient;

private TimeSpan _grpcTimeout;
private readonly TimeSpan _grpcTimeout;
private readonly ILogger _logger;

/// <summary>Instantiates a new Qdrant client.</summary>
Expand Down Expand Up @@ -768,6 +768,7 @@ public async Task UpdateAliasesAsync(
{
foreach (var operation in aliasOperations)
{
// ReSharper disable ConvertTypeCheckPatternToNullCheck
switch (operation)
{
case { CreateAlias: CreateAlias createAlias }:
Expand All @@ -784,7 +785,9 @@ public async Task UpdateAliasesAsync(

default:
throw new ArgumentOutOfRangeException();

}
// ReSharper restore ConvertTypeCheckPatternToNullCheck
}
}

Expand Down Expand Up @@ -1882,8 +1885,6 @@ public async Task<UpdateResult> CreatePayloadIndexAsync(
}
};

request.FieldType = FieldType.Keyword;

if (indexParams is not null)
{
request.FieldIndexParams = indexParams;
Expand Down Expand Up @@ -1943,7 +1944,7 @@ public async Task<UpdateResult> DeletePayloadIndexAsync(
request.Ordering = new() { Type = ordering.Value };
}

_logger.CreatePayloadIndex(collectionName);
_logger.DeletePayloadIndex(collectionName);

try
{
Expand All @@ -1957,7 +1958,7 @@ public async Task<UpdateResult> DeletePayloadIndexAsync(
}
catch (Exception e)
{
_logger.OperationFailed(nameof(LoggingExtensions.CreatePayloadIndex), e);
_logger.OperationFailed(nameof(LoggingExtensions.DeletePayloadIndex), e);

throw;
}
Expand Down
21 changes: 0 additions & 21 deletions src/Qdrant.Client/Vector.cs

This file was deleted.

91 changes: 56 additions & 35 deletions tests/Qdrant.Client.Tests/PointTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using FluentAssertions;
using Qdrant.Client.Grpc;
using Xunit;

Expand All @@ -15,17 +16,14 @@ public async Task Retrieve()
{
await CreateAndSeedCollection("collection_1");

var points = await _client.RetrieveAsync("collection_1", new[] { new PointId { Num = 9 } });

var point = Assert.Single(points);

Assert.Equal(9ul, point.Id.Num);

var payloadKeyValue = Assert.Single(point.Payload);
Assert.Equal("foo", payloadKeyValue.Key);
Assert.Equal("goodbye", payloadKeyValue.Value.StringValue);

Assert.Null(point.Vectors);
var points = await _client.RetrieveAsync("collection_1", new PointId[] { 9 });
points.Should().HaveCount(1);
var point = points.Single();
point.Id.Should().Be((PointId)9ul);
point.Payload.Should().ContainKeys("foo", "bar");
point.Payload["foo"].Should().Be((Value)"goodbye");
point.Payload["bar"].Should().Be((Value)2);
point.Vectors.Should().BeNull();
}

[Fact]
Expand All @@ -35,7 +33,7 @@ public async Task Retrieve_with_vector_without_payload()

var points = await _client.RetrieveAsync(
"collection_1",
new[] { new PointId { Num = 8 } },
new PointId[] { 8 },
withPayload: false,
withVectors: true);

Expand All @@ -55,7 +53,7 @@ await _client.SetPayloadAsync(
new Dictionary<string, Value> { ["bar"] = "some bar" },
new[] { 9ul });

var points = await _client.RetrieveAsync("collection_1", new[] { new PointId { Num = 9 } });
var points = await _client.RetrieveAsync("collection_1", new PointId[] { 9 });

var point = Assert.Single(points);
Assert.Collection(
Expand Down Expand Up @@ -101,7 +99,7 @@ await _client.SetPayloadAsync(

await _client.DeletePayloadAsync("collection_1", new[] { "foo" }, new[] { 9ul });

var points = await _client.RetrieveAsync("collection_1", new[] { new PointId { Num = 9 } });
var points = await _client.RetrieveAsync("collection_1", new PointId[] { 9 });

var point = Assert.Single(points);
var payloadKeyValue = Assert.Single(point.Payload);
Expand All @@ -116,7 +114,7 @@ public async Task ClearPayload()

await _client.ClearPayloadAsync("collection_1", new[] { 9ul });

var points = await _client.RetrieveAsync("collection_1", new[] { new PointId { Num = 9 } });
var points = await _client.RetrieveAsync("collection_1", new PointId[] { 9 });

var point = Assert.Single(points);
Assert.Empty(point.Payload);
Expand All @@ -127,16 +125,28 @@ public async Task CreateFieldIndex()
{
await CreateAndSeedCollection("collection_1");

await _client.CreatePayloadIndexAsync("collection_1", "foo");
var result = await _client.CreatePayloadIndexAsync("collection_1", "foo");
result.Status.Should().Be(UpdateStatus.Completed);

result = await _client.CreatePayloadIndexAsync("collection_1", "bar", PayloadSchemaType.Integer);
result.Status.Should().Be(UpdateStatus.Completed);

var collectionInfo = await _client.GetCollectionInfoAsync("collection_1");
collectionInfo.PayloadSchema.Should().ContainKeys("foo", "bar");
collectionInfo.PayloadSchema["foo"].DataType.Should().Be(PayloadSchemaType.Keyword);
collectionInfo.PayloadSchema["bar"].DataType.Should().Be(PayloadSchemaType.Integer);
}

[Fact]
public async Task DeleteFieldIndex()
{
await CreateAndSeedCollection("collection_1");
await _client.CreatePayloadIndexAsync("collection_1", "foo");

await _client.DeletePayloadIndexAsync("collection_1", "foo");
var result = await _client.CreatePayloadIndexAsync("collection_1", "foo");
result.Status.Should().Be(UpdateStatus.Completed);

result = await _client.DeletePayloadIndexAsync("collection_1", "foo");
result.Status.Should().Be(UpdateStatus.Completed);
}

[Fact]
Expand All @@ -149,12 +159,13 @@ public async Task Search()
new[] { 10.4f, 11.4f },
limit: 1);

var point = Assert.Single(points);

Assert.Equal(9ul, point.Id);
var payloadKeyValue = Assert.Single(point.Payload);
Assert.Equal("foo", payloadKeyValue.Key);
Assert.Equal("goodbye", payloadKeyValue.Value.StringValue);
points.Should().HaveCount(1);
var point = points.Single();
point.Id.Should().Be((PointId)9ul);
point.Payload.Should().ContainKeys("foo", "bar");
point.Payload["foo"].Should().Be((Value)"goodbye");
point.Payload["bar"].Should().Be((Value)2);
point.Vectors.Should().BeNull();
}

[Fact]
Expand Down Expand Up @@ -186,7 +197,7 @@ await _client.UpsertAsync("collection_1", new[]
new PointStruct
{
Id = new PointId { Num = 10 },
Vectors = new() { Vector = new() { Data = { 30f, 31f }} },
Vectors = new[] { 30f, 31f },
Payload = { ["foo"] = "hello" }
}
});
Expand Down Expand Up @@ -262,8 +273,8 @@ await _client.UpsertAsync("collection_1", new[]
{
new PointStruct
{
Id = new PointId { Num = 10 },
Vectors = new() { Vector = new() { Data = { 30f, 31f }} },
Id = 10,
Vectors = new[] { 30f, 31f },
Payload = { ["foo"] = "hello" }
}
});
Expand Down Expand Up @@ -295,7 +306,7 @@ public async Task Count_with_filter()
"collection_1",
new Filter
{
Must = { new Condition { HasId = new HasIdCondition { HasId = { new PointId { Num = 9 } } } } }
Must = { new Condition { HasId = new HasIdCondition { HasId = { 9 } } } }
});

Assert.Equal(1ul, count);
Expand All @@ -305,21 +316,31 @@ private async Task CreateAndSeedCollection(string collection)
{
await _client.CreateCollectionAsync(collection, new VectorParams { Size = 2, Distance = Distance.Cosine });

await _client.UpsertAsync(collection, new[]
var updateResult = await _client.UpsertAsync(collection, new[]
{
new PointStruct
{
Id = new PointId { Num = 8 },
Vectors = new() { Vector = new() { Data = { 3.5f, 4.5f }} },
Payload = { ["foo"] = "hello" }
Id = 8,
Vectors = new[] { 3.5f, 4.5f },
Payload =
{
["foo"] = "hello",
["bar"] = 1
}
},
new PointStruct
{
Id = new PointId { Num = 9 },
Vectors = new() { Vector = new() { Data = { 10.5f, 11.5f } } },
Payload = { ["foo"] = "goodbye" }
Id = 9,
Vectors = new[] { 10.5f, 11.5f },
Payload =
{
["foo"] = "goodbye",
["bar"] = 2
}
}
});

updateResult.Status.Should().Be(UpdateStatus.Completed);
}

public async Task InitializeAsync()
Expand Down

0 comments on commit 0b3bbb6

Please sign in to comment.