From df75cd25e0a1beb55be97d5fcb8a718806793f51 Mon Sep 17 00:00:00 2001
From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com>
Date: Sun, 5 Jan 2025 16:57:13 -0600
Subject: [PATCH] feat: add model to represent paged request
---
src/AnthropicClient/Models/PagingRequest.cs | 80 +++++++++++++++++++
.../Unit/Models/PagingRequestTests.cs | 70 ++++++++++++++++
2 files changed, 150 insertions(+)
create mode 100644 src/AnthropicClient/Models/PagingRequest.cs
create mode 100644 tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs
diff --git a/src/AnthropicClient/Models/PagingRequest.cs b/src/AnthropicClient/Models/PagingRequest.cs
new file mode 100644
index 0000000..b7aad83
--- /dev/null
+++ b/src/AnthropicClient/Models/PagingRequest.cs
@@ -0,0 +1,80 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+///
+/// Represents a request to page through a collection of items.
+///
+public class PagingRequest
+{
+ private const int LimitMinimum = 1;
+ private const int LimitMaximum = 1000;
+ private const int DefaultLimit = 20;
+
+ ///
+ /// The ID of the item before which to start the page.
+ ///
+ [JsonPropertyName("before_id")]
+ public string BeforeId { get; init; }
+
+ ///
+ /// The ID of the item after which to start the page.
+ ///
+ [JsonPropertyName("after_id")]
+ public string AfterId { get; init; }
+
+ ///
+ /// The maximum number of items to return in the page.
+ ///
+ public int Limit { get; init; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The ID of the item before which to start the page.
+ /// The ID of the item after which to start the page.
+ /// The maximum number of items to return in the page.
+ /// Thrown when is less than 1 or greater than 1000.
+ /// A new instance of the class.
+ public PagingRequest(
+ string beforeId = "",
+ string afterId = "",
+ int limit = DefaultLimit
+ )
+ {
+ if (limit is < LimitMinimum or > LimitMaximum)
+ {
+ throw new ArgumentOutOfRangeException(nameof(limit), $"{nameof(limit)} must be between {LimitMinimum} and {LimitMaximum}.");
+ }
+
+ BeforeId = beforeId;
+ AfterId = afterId;
+ Limit = limit;
+ }
+
+ ///
+ /// Converts the to a query string.
+ ///
+ /// The query string representation of the .
+ public string ToQueryParameters()
+ {
+ var parameters = new List();
+
+ if (string.IsNullOrEmpty(BeforeId) is false)
+ {
+ parameters.Add($"before_id={BeforeId}");
+ }
+
+ if (string.IsNullOrEmpty(AfterId) is false)
+ {
+ parameters.Add($"after_id={AfterId}");
+ }
+
+ if (Limit is not DefaultLimit)
+ {
+ parameters.Add($"limit={Limit}");
+ }
+
+ return string.Join("&", parameters);
+ }
+}
\ No newline at end of file
diff --git a/tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs b/tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs
new file mode 100644
index 0000000..54e6c8f
--- /dev/null
+++ b/tests/AnthropicClient.Tests/Unit/Models/PagingRequestTests.cs
@@ -0,0 +1,70 @@
+namespace AnthropicClient.Tests.Unit.Models;
+
+public class PagingRequestTests : SerializationTest
+{
+ [Fact]
+ public void Constructor_WhenLimitIsLessThanMinimum_ItShouldThrowArgumentOutOfRangeException()
+ {
+ var act = () => new PagingRequest(limit: 0);
+
+ act.Should().Throw().WithMessage("limit must be between 1 and 1000. (Parameter 'limit')");
+ }
+
+ [Fact]
+ public void Constructor_WhenLimitIsGreaterThanMaximum_ItShouldThrowArgumentOutOfRangeException()
+ {
+ var act = () => new PagingRequest(limit: 1001);
+
+ act.Should().Throw().WithMessage("limit must be between 1 and 1000. (Parameter 'limit')");
+ }
+
+ [Fact]
+ public void ToQueryParameters_WhenNoPropertiesSet_ItShouldReturnEmptyString()
+ {
+ var pagingRequest = new PagingRequest();
+
+ var result = pagingRequest.ToQueryParameters();
+
+ result.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void ToQueryParameters_WhenBeforeIdIsSet_ItShouldReturnBeforeId()
+ {
+ var pagingRequest = new PagingRequest(beforeId: "before-id");
+
+ var result = pagingRequest.ToQueryParameters();
+
+ result.Should().Be("before_id=before-id");
+ }
+
+ [Fact]
+ public void ToQueryParameters_WhenAfterIdIsSet_ItShouldReturnAfterId()
+ {
+ var pagingRequest = new PagingRequest(afterId: "after-id");
+
+ var result = pagingRequest.ToQueryParameters();
+
+ result.Should().Be("after_id=after-id");
+ }
+
+ [Fact]
+ public void ToQueryParameters_WhenLimitIsSetToNonDefaultValue_ItShouldReturnLimit()
+ {
+ var pagingRequest = new PagingRequest(limit: 10);
+
+ var result = pagingRequest.ToQueryParameters();
+
+ result.Should().Be("limit=10");
+ }
+
+ [Fact]
+ public void ToQueryParameters_WhenAllPropertiesAreSet_ItShouldReturnAllProperties()
+ {
+ var pagingRequest = new PagingRequest(beforeId: "before-id", afterId: "after-id", limit: 10);
+
+ var result = pagingRequest.ToQueryParameters();
+
+ result.Should().Be("before_id=before-id&after_id=after-id&limit=10");
+ }
+}
\ No newline at end of file