Skip to content

Commit

Permalink
feat: align impl. with API changes, document collection types, make i…
Browse files Browse the repository at this point in the history
…nternal types non-record - there is no need to spend extra IL/AOT size on that
  • Loading branch information
neon-sunset committed Sep 26, 2024
1 parent feabe70 commit 8276c3c
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 66 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ if (!indexes.Contains(indexName))
await pinecone.CreateServerlessIndex(indexName, 1536, Metric.Cosine, "aws", "us-east-1");
}

// Get the Pinecone index by name (uses gRPC by default).
// Get the Pinecone index by name (uses REST by default).
// The index client is thread-safe, consider caching and/or
// injecting it as a singleton into your DI container.
using var index = await pinecone.GetIndex(indexName);
Expand Down
2 changes: 1 addition & 1 deletion example/Example.FSharp/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ let main = task {
// free serverless indexes are currently only available on AWS us-east-1
do! pinecone.CreateServerlessIndex(indexName, 1536u, Metric.Cosine, "aws", "us-east-1")

// Get the Pinecone index by name (uses gRPC by default).
// Get the Pinecone index by name (uses REST by default).
// The index client is thread-safe, consider caching and/or
// injecting it as a singleton into your DI container.
use! index = pinecone.GetIndex(indexName)
Expand Down
1 change: 0 additions & 1 deletion src/Grpc/GrpcTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ public async Task<IndexStats> DescribeStats(MetadataMap? filter = null, Cancella

using var call = Grpc.QueryAsync(request, Metadata, cancellationToken: ct);
var response = await call.ConfigureAwait(false);

var matches = response.Matches;
var vectors = new Pinecone.ScoredVector[response.Matches.Count];
for (var i = 0; i < matches.Count; i++)
Expand Down
2 changes: 1 addition & 1 deletion src/Index.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public sealed partial record Index<
/// <summary>
/// The URL address where the index is hosted.
/// </summary>
public string? Host { get; init; }
public required string Host { get; init; }

/// <summary>
/// Additional information about the index.
Expand Down
52 changes: 32 additions & 20 deletions src/PineconeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,9 @@ public PineconeClient(string apiKey, HttpClient client, ILoggerFactory? loggerFa
/// <returns>List of index descriptions for all indexes in the project.</returns>
public async Task<IndexDetails[]> ListIndexes(CancellationToken ct = default)
{
var listIndexesResult = await Http
return (await Http
.GetFromJsonAsync("/indexes", ClientContext.Default.ListIndexesResult, ct)
.ConfigureAwait(false);

return listIndexesResult?.Indexes ?? [];
.ConfigureAwait(false)).Indexes;
}

/// <summary>
Expand All @@ -92,9 +90,9 @@ public Task CreatePodBasedIndex(
Metric metric,
string environment,
string podType = "p1.x1",
uint? pods = 1,
uint? shards = 1,
uint? replicas = 1,
uint pods = 1,
uint shards = 1,
uint replicas = 1,
CancellationToken ct = default)
{
return CreateIndex(new CreateIndexRequest
Expand Down Expand Up @@ -135,7 +133,7 @@ public Task CreateServerlessIndex(

private async Task CreateIndex(CreateIndexRequest request, CancellationToken ct = default)
{
var response = await Http
using var response = await Http
.PostAsJsonAsync("/indexes", request, ClientContext.Default.CreateIndexRequest, ct)
.ConfigureAwait(false);
await response.CheckStatusCode(ct).ConfigureAwait(false);
Expand Down Expand Up @@ -180,9 +178,6 @@ public async Task<Index<TTransport>> GetIndex<
.GetFromJsonAsync($"/indexes/{UrlEncoder.Default.Encode(name)}", ClientContext.Default.IndexDetails, ct)
.ConfigureAwait(false) ?? throw new HttpRequestException("GetIndex request has failed.");

// TODO: Host is optional according to the API spec: https://docs.pinecone.io/reference/api/control-plane/describe_index
// but Transport requires it
var host = response.Host!;
var apiKey = Http.DefaultRequestHeaders.GetValues(Constants.RestApiKey).First();

var index = new Index<TTransport>(LoggerFactory)
Expand All @@ -194,11 +189,11 @@ public async Task<Index<TTransport>> GetIndex<
Spec = response.Spec,
Status = response.Status,
#if NET7_0_OR_GREATER
Transport = TTransport.Create(host, apiKey, LoggerFactory)
Transport = TTransport.Create(response.Host, apiKey, LoggerFactory)
#elif NET6_0
Transport = ITransport<TTransport>.Create(host, apiKey, LoggerFactory)
Transport = ITransport<TTransport>.Create(response.Host, apiKey, LoggerFactory)
#else
Transport = CreateTransport<TTransport>(host, apiKey, LoggerFactory)
Transport = CreateTransport<TTransport>(response.Host, apiKey, LoggerFactory)
#endif
};

Expand Down Expand Up @@ -232,16 +227,33 @@ internal static T CreateTransport<T>(string host, string apiKey, ILoggerFactory?
/// <param name="replicas">The new number or replicas.</param>
/// <param name="podType">The new pod type.</param>
/// <param name="ct">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
public async Task ConfigureIndex(string name, int? replicas = null, string? podType = null, CancellationToken ct = default)
public async Task ConfigureIndex(
string name,
DeletionProtection? deletionProtection = null,
int? replicas = null,
string? podType = null,
CancellationToken ct = default)
{
if (replicas is null && podType is null or [])
if (deletionProtection is null && replicas is null && podType is null or [])
{
ThrowHelpers.ArgumentException(
"At least one of the following parameters must be specified: replicas, podType.");
"At least one of the following parameters must be specified: deletionProtection, replicas or podType.");
}

var request = new ConfigureIndexRequest { Replicas = replicas, PodType = podType };
var response = await Http
var request = new ConfigureIndexRequest
{
Spec = (replicas != null || podType != null) ? new()
{
Pod = new()
{
Replicas = replicas,
PodType = podType
}
} : null,
DeletionProtection = deletionProtection
};

using var response = await Http
.PatchAsJsonAsync(
$"/indexes/{UrlEncoder.Default.Encode(name)}",
request,
Expand Down Expand Up @@ -285,7 +297,7 @@ public async Task<CollectionDetails[]> ListCollections(CancellationToken ct = de
public async Task CreateCollection(string name, string source, CancellationToken ct = default)
{
var request = new CreateCollectionRequest { Name = name, Source = source };
var response = await Http
using var response = await Http
.PostAsJsonAsync("/collections", request, ClientContext.Default.CreateCollectionRequest, ct)
.ConfigureAwait(false);

Expand Down
14 changes: 7 additions & 7 deletions src/Rest/RestTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ public RestTransport(string host, string apiKey, ILoggerFactory? loggerFactory)
public async Task<IndexStats> DescribeStats(MetadataMap? filter = null, CancellationToken ct = default)
{
var request = new DescribeStatsRequest { Filter = filter };
var response = await Http
using var response = await Http
.PostAsJsonAsync("/describe_index_stats", request, RestTransportContext.Default.DescribeStatsRequest, ct)
.ConfigureAwait(false);

return await response.Content
.ReadFromJsonAsync(RestTransportContext.Default.IndexStats, ct)
.ConfigureAwait(false) ?? ThrowHelpers.JsonException<IndexStats>();
.ConfigureAwait(false);
}

public async Task<ScoredVector[]> Query(
Expand Down Expand Up @@ -64,7 +64,7 @@ public async Task<ScoredVector[]> Query(
IncludeValues = includeValues,
};

var response = await Http
using var response = await Http
.PostAsJsonAsync("/query", request, RestTransportContext.Default.QueryRequest, ct)
.ConfigureAwait(false);

Expand All @@ -82,7 +82,7 @@ public async Task<uint> Upsert(IEnumerable<Vector> vectors, string? indexNamespa
Namespace = indexNamespace ?? ""
};

var response = await Http
using var response = await Http
.PostAsJsonAsync("/vectors/upsert", request, RestTransportContext.Default.UpsertRequest, ct)
.ConfigureAwait(false);

Expand All @@ -102,7 +102,7 @@ public async Task Update(Vector vector, string? indexNamespace = null, Cancellat
Namespace = indexNamespace ?? ""
};

var response = await Http
using var response = await Http
.PostAsJsonAsync("/vectors/update", request, RestTransportContext.Default.UpdateRequest, ct)
.ConfigureAwait(false);

Expand Down Expand Up @@ -132,7 +132,7 @@ public async Task Update(
Namespace = indexNamespace ?? ""
};

var response = await Http
using var response = await Http
.PostAsJsonAsync("/vectors/update", request, RestTransportContext.Default.UpdateRequest, ct)
.ConfigureAwait(false);

Expand Down Expand Up @@ -222,7 +222,7 @@ public Task DeleteAll(string? indexNamespace = null, CancellationToken ct = defa

private async Task Delete(DeleteRequest request, CancellationToken ct)
{
var response = await Http
using var response = await Http
.PostAsJsonAsync("/vectors/delete", request, RestTransportContext.Default.DeleteRequest, ct)
.ConfigureAwait(false);
await response.CheckStatusCode(ct).ConfigureAwait(false);
Expand Down
46 changes: 28 additions & 18 deletions src/Rest/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,54 @@

namespace Pinecone.Rest;

sealed record ListIndexesResult
readonly struct ListIndexesResult
{
public required IndexDetails[] Indexes { get; init; }
}

sealed record CreateIndexRequest
sealed class CreateIndexRequest
{
public required string Name { get; init; }
public required uint Dimension { get; init; }
public required Metric Metric { get; init; }
public required IndexSpec Spec { get; init; }
}

readonly record struct ConfigureIndexRequest
readonly struct ConfigureIndexRequest
{
public int? Replicas { get; init; }

[JsonPropertyName("pod_type")]
public string? PodType { get; init; }
public readonly struct ConfigureIndexSpec
{
public required PodConfig Pod { get; init; }
}

public readonly struct PodConfig
{
public int? Replicas { get; init; }
[JsonPropertyName("pod_type")]
public string? PodType { get; init; }
}

public ConfigureIndexSpec? Spec { get; init; }
public DeletionProtection? DeletionProtection { get; init; }
}

readonly record struct DescribeStatsRequest
readonly struct DescribeStatsRequest
{
public MetadataMap? Filter { get; init; }
}

readonly record struct CreateCollectionRequest
readonly struct CreateCollectionRequest
{
public required string Name { get; init; }
public required string Source { get; init; }
}

readonly record struct ListCollectionsResult
readonly struct ListCollectionsResult
{
public required CollectionDetails[] Collections { get; init; }
}

record QueryRequest
sealed class QueryRequest
{
public string? Id { get; set; }
public ReadOnlyMemory<float>? Vector { get; set; }
Expand All @@ -51,24 +61,24 @@ record QueryRequest
public required bool IncludeMetadata { get; init; }
}

readonly record struct QueryResponse
readonly struct QueryResponse
{
public required ScoredVector[] Matches { get; init; }
public required string Namespace { get; init; }
}

readonly record struct UpsertRequest
readonly struct UpsertRequest
{
public required IEnumerable<Vector> Vectors { get; init; }
public required string Namespace { get; init; }
}

readonly record struct UpsertResponse
readonly struct UpsertResponse
{
public required uint UpsertedCount { get; init; }
}

record UpdateRequest
sealed class UpdateRequest
{
public required string Id { get; init; }
public ReadOnlyMemory<float>? Values { get; init; }
Expand All @@ -77,7 +87,7 @@ record UpdateRequest
public required string Namespace { get; init; }
}

readonly record struct ListResponse
readonly struct ListResponse
{
public readonly record struct ListVector(string Id);
public readonly record struct ListPagination(string? Next);
Expand All @@ -89,13 +99,13 @@ readonly record struct ListResponse
}


readonly record struct FetchResponse
readonly struct FetchResponse
{
public required Dictionary<string, Vector> Vectors { get; init; }
public required string Namespace { get; init; }
}

readonly record struct DeleteRequest
readonly struct DeleteRequest
{
public string[]? Ids { get; init; }
public required bool DeleteAll { get; init; }
Expand Down
33 changes: 31 additions & 2 deletions src/Types/CollectionTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,46 @@

namespace Pinecone;

/// <summary>
/// Object storing information about the collection.
/// </summary>
public record CollectionDetails
{
/// <summary>
/// The name of the collection.
/// </summary>
public required string Name { get; init; }

/// <summary>
/// The size of the collection in bytes.
/// </summary>
public long? Size { get; init; }

/// <summary>
/// The status of the collection.
/// </summary>
public required CollectionStatus Status { get; init; }
public required uint Dimension { get; init; }

/// <summary>
/// The dimension of the vectors stored in each record held in the collection.
/// </summary>
public uint? Dimension { get; init; }

/// <summary>
/// The number of records stored in the collection.
/// </summary>
[JsonPropertyName("vector_count")]
public required long VectorCount { get; init; }
public long? VectorCount { get; init; }

/// <summary>
/// The environment where the collection is hosted.
/// </summary>
public required string Environment { get; init; }
}

/// <summary>
/// Current status of the collection.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter<CollectionStatus>))]
public enum CollectionStatus
{
Expand Down
Loading

0 comments on commit 8276c3c

Please sign in to comment.