From a44b0cc87fedef4d2c934b2bae236c3c38ea001e Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 9 May 2026 14:16:41 +0100 Subject: [PATCH] Enhance Smartphones API with pagination and count endpoints - Updated SmartphonesRequestBuilder to support pagination with skip and take query parameters. - Added new CountRequestBuilder for counting smartphones by letter and year. - Modified SmartphonesController to handle pagination in GetSmartphonesByLetterAsync and GetSmartphonesByYearAsync methods. - Updated Search.razor and Search.razor.cs to implement infinite scrolling and display total smartphone count. - Enhanced SmartphonesService to support pagination and count retrieval for smartphones. - Added new Count endpoints for prototypes and by year in the API client. --- .../Item/Count/CountRequestBuilder.cs | 91 ++++++++++ .../ByLetter/Item/WithCItemRequestBuilder.cs | 30 +++- .../ByYear/Item/Count/CountRequestBuilder.cs | 91 ++++++++++ .../ByYear/Item/WithYearItemRequestBuilder.cs | 30 +++- .../Prototypes/Count/CountRequestBuilder.cs | 91 ++++++++++ .../Prototypes/PrototypesRequestBuilder.cs | 30 +++- .../Smartphones/SmartphonesRequestBuilder.cs | 24 ++- Marechai.ApiClient/kiota-lock.json | 2 +- .../Controllers/SmartphonesController.cs | 169 ++++++++++++------ Marechai/Pages/Smartphones/Search.razor | 26 ++- Marechai/Pages/Smartphones/Search.razor.cs | 162 ++++++++++++++--- Marechai/Services/SmartphonesService.cs | 80 ++++++++- 12 files changed, 702 insertions(+), 124 deletions(-) create mode 100644 Marechai.ApiClient/Smartphones/ByLetter/Item/Count/CountRequestBuilder.cs create mode 100644 Marechai.ApiClient/Smartphones/ByYear/Item/Count/CountRequestBuilder.cs create mode 100644 Marechai.ApiClient/Smartphones/Prototypes/Count/CountRequestBuilder.cs diff --git a/Marechai.ApiClient/Smartphones/ByLetter/Item/Count/CountRequestBuilder.cs b/Marechai.ApiClient/Smartphones/ByLetter/Item/Count/CountRequestBuilder.cs new file mode 100644 index 00000000..984a6b8f --- /dev/null +++ b/Marechai.ApiClient/Smartphones/ByLetter/Item/Count/CountRequestBuilder.cs @@ -0,0 +1,91 @@ +// +#pragma warning disable CS0618 +using Marechai.ApiClient.Models; +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Marechai.ApiClient.Smartphones.ByLetter.Item.Count +{ + /// + /// Builds and executes requests for operations under \smartphones\by-letter\{c}\count + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CountRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public CountRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-letter/{c}/count", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public CountRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-letter/{c}/count", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Marechai.ApiClient.Models.ProblemDetails.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Marechai.ApiClient.Smartphones.ByLetter.Item.Count.CountRequestBuilder WithUrl(string rawUrl) + { + return new global::Marechai.ApiClient.Smartphones.ByLetter.Item.Count.CountRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CountRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/Marechai.ApiClient/Smartphones/ByLetter/Item/WithCItemRequestBuilder.cs b/Marechai.ApiClient/Smartphones/ByLetter/Item/WithCItemRequestBuilder.cs index 2d4d7dad..1f5f9bde 100644 --- a/Marechai.ApiClient/Smartphones/ByLetter/Item/WithCItemRequestBuilder.cs +++ b/Marechai.ApiClient/Smartphones/ByLetter/Item/WithCItemRequestBuilder.cs @@ -1,6 +1,7 @@ // #pragma warning disable CS0618 using Marechai.ApiClient.Models; +using Marechai.ApiClient.Smartphones.ByLetter.Item.Count; using Microsoft.Kiota.Abstractions.Extensions; using Microsoft.Kiota.Abstractions.Serialization; using Microsoft.Kiota.Abstractions; @@ -17,12 +18,17 @@ namespace Marechai.ApiClient.Smartphones.ByLetter.Item [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] public partial class WithCItemRequestBuilder : BaseRequestBuilder { + /// The count property + public global::Marechai.ApiClient.Smartphones.ByLetter.Item.Count.CountRequestBuilder Count + { + get => new global::Marechai.ApiClient.Smartphones.ByLetter.Item.Count.CountRequestBuilder(PathParameters, RequestAdapter); + } /// /// Instantiates a new and sets the default values. /// /// Path parameters for the request /// The request adapter to use to execute the requests. - public WithCItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-letter/{c}", pathParameters) + public WithCItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-letter/{c}{?skip*,take*}", pathParameters) { } /// @@ -30,7 +36,7 @@ namespace Marechai.ApiClient.Smartphones.ByLetter.Item /// /// The raw URL to use for the request builder. /// The request adapter to use to execute the requests. - public WithCItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-letter/{c}", rawUrl) + public WithCItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-letter/{c}{?skip*,take*}", rawUrl) { } /// A List<global::Marechai.ApiClient.Models.MachineDto> @@ -39,11 +45,11 @@ namespace Marechai.ApiClient.Smartphones.ByLetter.Item /// When receiving a 400 status code #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) { #nullable restore #else - public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) { #endif var requestInfo = ToGetRequestInformation(requestConfiguration); @@ -58,11 +64,11 @@ namespace Marechai.ApiClient.Smartphones.ByLetter.Item /// Configuration for the request such as headers, query parameters, and middleware options. #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) { #nullable restore #else - public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) { #endif var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); @@ -79,12 +85,22 @@ namespace Marechai.ApiClient.Smartphones.ByLetter.Item { return new global::Marechai.ApiClient.Smartphones.ByLetter.Item.WithCItemRequestBuilder(rawUrl, RequestAdapter); } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithCItemRequestBuilderGetQueryParameters + #pragma warning restore CS1591 + { + [QueryParameter("skip")] + public int? Skip { get; set; } + [QueryParameter("take")] + public int? Take { get; set; } + } /// /// Configuration for the request such as headers, query parameters, and middleware options. /// [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] - public partial class WithCItemRequestBuilderGetRequestConfiguration : RequestConfiguration + public partial class WithCItemRequestBuilderGetRequestConfiguration : RequestConfiguration { } } diff --git a/Marechai.ApiClient/Smartphones/ByYear/Item/Count/CountRequestBuilder.cs b/Marechai.ApiClient/Smartphones/ByYear/Item/Count/CountRequestBuilder.cs new file mode 100644 index 00000000..7c1db4ee --- /dev/null +++ b/Marechai.ApiClient/Smartphones/ByYear/Item/Count/CountRequestBuilder.cs @@ -0,0 +1,91 @@ +// +#pragma warning disable CS0618 +using Marechai.ApiClient.Models; +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Marechai.ApiClient.Smartphones.ByYear.Item.Count +{ + /// + /// Builds and executes requests for operations under \smartphones\by-year\{year}\count + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CountRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public CountRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-year/{year}/count", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public CountRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-year/{year}/count", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Marechai.ApiClient.Models.ProblemDetails.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Marechai.ApiClient.Smartphones.ByYear.Item.Count.CountRequestBuilder WithUrl(string rawUrl) + { + return new global::Marechai.ApiClient.Smartphones.ByYear.Item.Count.CountRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CountRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/Marechai.ApiClient/Smartphones/ByYear/Item/WithYearItemRequestBuilder.cs b/Marechai.ApiClient/Smartphones/ByYear/Item/WithYearItemRequestBuilder.cs index d8be308c..dd7dc299 100644 --- a/Marechai.ApiClient/Smartphones/ByYear/Item/WithYearItemRequestBuilder.cs +++ b/Marechai.ApiClient/Smartphones/ByYear/Item/WithYearItemRequestBuilder.cs @@ -1,6 +1,7 @@ // #pragma warning disable CS0618 using Marechai.ApiClient.Models; +using Marechai.ApiClient.Smartphones.ByYear.Item.Count; using Microsoft.Kiota.Abstractions.Extensions; using Microsoft.Kiota.Abstractions.Serialization; using Microsoft.Kiota.Abstractions; @@ -17,12 +18,17 @@ namespace Marechai.ApiClient.Smartphones.ByYear.Item [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] public partial class WithYearItemRequestBuilder : BaseRequestBuilder { + /// The count property + public global::Marechai.ApiClient.Smartphones.ByYear.Item.Count.CountRequestBuilder Count + { + get => new global::Marechai.ApiClient.Smartphones.ByYear.Item.Count.CountRequestBuilder(PathParameters, RequestAdapter); + } /// /// Instantiates a new and sets the default values. /// /// Path parameters for the request /// The request adapter to use to execute the requests. - public WithYearItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-year/{year}", pathParameters) + public WithYearItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-year/{year}{?skip*,take*}", pathParameters) { } /// @@ -30,7 +36,7 @@ namespace Marechai.ApiClient.Smartphones.ByYear.Item /// /// The raw URL to use for the request builder. /// The request adapter to use to execute the requests. - public WithYearItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-year/{year}", rawUrl) + public WithYearItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/by-year/{year}{?skip*,take*}", rawUrl) { } /// A List<global::Marechai.ApiClient.Models.MachineDto> @@ -39,11 +45,11 @@ namespace Marechai.ApiClient.Smartphones.ByYear.Item /// When receiving a 400 status code #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) { #nullable restore #else - public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) { #endif var requestInfo = ToGetRequestInformation(requestConfiguration); @@ -58,11 +64,11 @@ namespace Marechai.ApiClient.Smartphones.ByYear.Item /// Configuration for the request such as headers, query parameters, and middleware options. #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) { #nullable restore #else - public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) { #endif var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); @@ -79,12 +85,22 @@ namespace Marechai.ApiClient.Smartphones.ByYear.Item { return new global::Marechai.ApiClient.Smartphones.ByYear.Item.WithYearItemRequestBuilder(rawUrl, RequestAdapter); } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithYearItemRequestBuilderGetQueryParameters + #pragma warning restore CS1591 + { + [QueryParameter("skip")] + public int? Skip { get; set; } + [QueryParameter("take")] + public int? Take { get; set; } + } /// /// Configuration for the request such as headers, query parameters, and middleware options. /// [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] - public partial class WithYearItemRequestBuilderGetRequestConfiguration : RequestConfiguration + public partial class WithYearItemRequestBuilderGetRequestConfiguration : RequestConfiguration { } } diff --git a/Marechai.ApiClient/Smartphones/Prototypes/Count/CountRequestBuilder.cs b/Marechai.ApiClient/Smartphones/Prototypes/Count/CountRequestBuilder.cs new file mode 100644 index 00000000..6567690b --- /dev/null +++ b/Marechai.ApiClient/Smartphones/Prototypes/Count/CountRequestBuilder.cs @@ -0,0 +1,91 @@ +// +#pragma warning disable CS0618 +using Marechai.ApiClient.Models; +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Marechai.ApiClient.Smartphones.Prototypes.Count +{ + /// + /// Builds and executes requests for operations under \smartphones\prototypes\count + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CountRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public CountRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/prototypes/count", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public CountRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/prototypes/count", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Marechai.ApiClient.Models.ProblemDetails.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Marechai.ApiClient.Smartphones.Prototypes.Count.CountRequestBuilder WithUrl(string rawUrl) + { + return new global::Marechai.ApiClient.Smartphones.Prototypes.Count.CountRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CountRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/Marechai.ApiClient/Smartphones/Prototypes/PrototypesRequestBuilder.cs b/Marechai.ApiClient/Smartphones/Prototypes/PrototypesRequestBuilder.cs index e1772a16..aece41c6 100644 --- a/Marechai.ApiClient/Smartphones/Prototypes/PrototypesRequestBuilder.cs +++ b/Marechai.ApiClient/Smartphones/Prototypes/PrototypesRequestBuilder.cs @@ -1,6 +1,7 @@ // #pragma warning disable CS0618 using Marechai.ApiClient.Models; +using Marechai.ApiClient.Smartphones.Prototypes.Count; using Microsoft.Kiota.Abstractions.Extensions; using Microsoft.Kiota.Abstractions.Serialization; using Microsoft.Kiota.Abstractions; @@ -17,12 +18,17 @@ namespace Marechai.ApiClient.Smartphones.Prototypes [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] public partial class PrototypesRequestBuilder : BaseRequestBuilder { + /// The count property + public global::Marechai.ApiClient.Smartphones.Prototypes.Count.CountRequestBuilder Count + { + get => new global::Marechai.ApiClient.Smartphones.Prototypes.Count.CountRequestBuilder(PathParameters, RequestAdapter); + } /// /// Instantiates a new and sets the default values. /// /// Path parameters for the request /// The request adapter to use to execute the requests. - public PrototypesRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/prototypes", pathParameters) + public PrototypesRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/prototypes{?skip*,take*}", pathParameters) { } /// @@ -30,7 +36,7 @@ namespace Marechai.ApiClient.Smartphones.Prototypes /// /// The raw URL to use for the request builder. /// The request adapter to use to execute the requests. - public PrototypesRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/prototypes", rawUrl) + public PrototypesRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones/prototypes{?skip*,take*}", rawUrl) { } /// A List<global::Marechai.ApiClient.Models.MachineDto> @@ -39,11 +45,11 @@ namespace Marechai.ApiClient.Smartphones.Prototypes /// When receiving a 400 status code #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) { #nullable restore #else - public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) { #endif var requestInfo = ToGetRequestInformation(requestConfiguration); @@ -58,11 +64,11 @@ namespace Marechai.ApiClient.Smartphones.Prototypes /// Configuration for the request such as headers, query parameters, and middleware options. #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) { #nullable restore #else - public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) { #endif var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); @@ -79,12 +85,22 @@ namespace Marechai.ApiClient.Smartphones.Prototypes { return new global::Marechai.ApiClient.Smartphones.Prototypes.PrototypesRequestBuilder(rawUrl, RequestAdapter); } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class PrototypesRequestBuilderGetQueryParameters + #pragma warning restore CS1591 + { + [QueryParameter("skip")] + public int? Skip { get; set; } + [QueryParameter("take")] + public int? Take { get; set; } + } /// /// Configuration for the request such as headers, query parameters, and middleware options. /// [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] - public partial class PrototypesRequestBuilderGetRequestConfiguration : RequestConfiguration + public partial class PrototypesRequestBuilderGetRequestConfiguration : RequestConfiguration { } } diff --git a/Marechai.ApiClient/Smartphones/SmartphonesRequestBuilder.cs b/Marechai.ApiClient/Smartphones/SmartphonesRequestBuilder.cs index 11477018..bf80f782 100644 --- a/Marechai.ApiClient/Smartphones/SmartphonesRequestBuilder.cs +++ b/Marechai.ApiClient/Smartphones/SmartphonesRequestBuilder.cs @@ -64,7 +64,7 @@ namespace Marechai.ApiClient.Smartphones /// /// Path parameters for the request /// The request adapter to use to execute the requests. - public SmartphonesRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones", pathParameters) + public SmartphonesRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones{?skip*,take*}", pathParameters) { } /// @@ -72,7 +72,7 @@ namespace Marechai.ApiClient.Smartphones /// /// The raw URL to use for the request builder. /// The request adapter to use to execute the requests. - public SmartphonesRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones", rawUrl) + public SmartphonesRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/smartphones{?skip*,take*}", rawUrl) { } /// A List<global::Marechai.ApiClient.Models.MachineDto> @@ -81,11 +81,11 @@ namespace Marechai.ApiClient.Smartphones /// When receiving a 400 status code #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) { #nullable restore #else - public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) { #endif var requestInfo = ToGetRequestInformation(requestConfiguration); @@ -100,11 +100,11 @@ namespace Marechai.ApiClient.Smartphones /// Configuration for the request such as headers, query parameters, and middleware options. #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER #nullable enable - public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) { #nullable restore #else - public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) { #endif var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); @@ -121,12 +121,22 @@ namespace Marechai.ApiClient.Smartphones { return new global::Marechai.ApiClient.Smartphones.SmartphonesRequestBuilder(rawUrl, RequestAdapter); } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class SmartphonesRequestBuilderGetQueryParameters + #pragma warning restore CS1591 + { + [QueryParameter("skip")] + public int? Skip { get; set; } + [QueryParameter("take")] + public int? Take { get; set; } + } /// /// Configuration for the request such as headers, query parameters, and middleware options. /// [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] - public partial class SmartphonesRequestBuilderGetRequestConfiguration : RequestConfiguration + public partial class SmartphonesRequestBuilderGetRequestConfiguration : RequestConfiguration { } } diff --git a/Marechai.ApiClient/kiota-lock.json b/Marechai.ApiClient/kiota-lock.json index f6950116..9461f787 100644 --- a/Marechai.ApiClient/kiota-lock.json +++ b/Marechai.ApiClient/kiota-lock.json @@ -1,5 +1,5 @@ { - "descriptionHash": "4E08D950A0D9E3D626B689AD691DC24BCA2478D82B6D0A73A6A1D80383CB7897EE7428C2FDC1AA1C8BEB56CB97EAA53C97F2EB535A39CAC7A257024ECBC52AB7", + "descriptionHash": "DE8F8DE43202CD0088961BD423206A3DD0A796459AA0CBC25F38B876E309CA69E68277197810ABC0C9EE80930AC13381BB614334CF9677C87DCB8241BE192BA8", "descriptionLocation": "../../../../../tmp/openapi.json", "lockFileVersion": "1.0.0", "kiotaVersion": "1.31.1", diff --git a/Marechai.Server/Controllers/SmartphonesController.cs b/Marechai.Server/Controllers/SmartphonesController.cs index 34fce5f4..cecbfe3d 100644 --- a/Marechai.Server/Controllers/SmartphonesController.cs +++ b/Marechai.Server/Controllers/SmartphonesController.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Marechai.Data; using Marechai.Data.Dtos; @@ -70,75 +71,135 @@ public class SmartphonesController(MarechaiContext context) : ControllerBase [AllowAnonymous] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public Task> GetSmartphonesByLetterAsync(char c) => context.Machines.Include(m => m.Company) - .Where(m => - m.Type == MachineType.Smartphone && - EF.Functions.Like(m.Name, $"{c}%")) - .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) - .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)) - .Select(m => new MachineDto - { - Id = m.Id, - Name = m.Name, - Company = m.Company.Name, - Introduced = m.Introduced - }) - .ToListAsync(); + public Task> GetSmartphonesByLetterAsync(char c, [FromQuery] int? skip = null, + [FromQuery] int? take = null, + CancellationToken cancellationToken = default) + { + IQueryable ordered = context.Machines.Include(m => m.Company) + .Where(m => m.Type == MachineType.Smartphone && + EF.Functions.Like(m.Name, $"{c}%")) + .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) + .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)); + + if(skip.HasValue) ordered = ordered.Skip(skip.Value); + if(take.HasValue) ordered = ordered.Take(take.Value); + + return ordered.Select(m => new MachineDto + { + Id = m.Id, + Name = m.Name, + Company = m.Company.Name, + Introduced = m.Introduced + }) + .ToListAsync(cancellationToken); + } + + [HttpGet("by-letter/{c}/count")] + [AllowAnonymous] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public Task GetSmartphonesByLetterCountAsync(char c, CancellationToken cancellationToken = default) => + context.Machines + .Where(m => m.Type == MachineType.Smartphone && EF.Functions.Like(m.Name, $"{c}%")) + .CountAsync(cancellationToken); [HttpGet("by-year/{year:int}")] [AllowAnonymous] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public Task> GetSmartphonesByYearAsync(int year) => context.Machines.Include(m => m.Company) - .Where(m => - m.Type == MachineType.Smartphone && - m.Introduced != null && - m.Introduced.Value.Year == year) - .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) - .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)) - .Select(m => new MachineDto - { - Id = m.Id, - Name = m.Name, - Company = m.Company.Name, - Introduced = m.Introduced - }) - .ToListAsync(); + public Task> GetSmartphonesByYearAsync(int year, [FromQuery] int? skip = null, + [FromQuery] int? take = null, + CancellationToken cancellationToken = default) + { + IQueryable ordered = context.Machines.Include(m => m.Company) + .Where(m => m.Type == MachineType.Smartphone && + m.Introduced != null && + m.Introduced.Value.Year == year) + .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) + .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)); + + if(skip.HasValue) ordered = ordered.Skip(skip.Value); + if(take.HasValue) ordered = ordered.Take(take.Value); + + return ordered.Select(m => new MachineDto + { + Id = m.Id, + Name = m.Name, + Company = m.Company.Name, + Introduced = m.Introduced + }) + .ToListAsync(cancellationToken); + } + + [HttpGet("by-year/{year:int}/count")] + [AllowAnonymous] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public Task GetSmartphonesByYearCountAsync(int year, CancellationToken cancellationToken = default) => + context.Machines + .Where(m => m.Type == MachineType.Smartphone && + m.Introduced != null && + m.Introduced.Value.Year == year) + .CountAsync(cancellationToken); [HttpGet] [AllowAnonymous] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public Task> GetSmartphonesAsync() => context.Machines.Include(m => m.Company) - .Where(m => m.Type == MachineType.Smartphone) - .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) - .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)) - .Select(m => new MachineDto - { - Id = m.Id, - Name = m.Name, - Company = m.Company.Name, - Introduced = m.Introduced - }) - .ToListAsync(); + public Task> GetSmartphonesAsync([FromQuery] int? skip = null, [FromQuery] int? take = null, + CancellationToken cancellationToken = default) + { + IQueryable ordered = context.Machines.Include(m => m.Company) + .Where(m => m.Type == MachineType.Smartphone) + .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) + .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)); + + if(skip.HasValue) ordered = ordered.Skip(skip.Value); + if(take.HasValue) ordered = ordered.Take(take.Value); + + return ordered.Select(m => new MachineDto + { + Id = m.Id, + Name = m.Name, + Company = m.Company.Name, + Introduced = m.Introduced + }) + .ToListAsync(cancellationToken); + } [HttpGet("prototypes")] [AllowAnonymous] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public Task> GetPrototypesAsync() => context.Machines.Include(m => m.Company) - .Where(m => m.Type == MachineType.Smartphone && - m.Prototype) - .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) - .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)) - .Select(m => new MachineDto - { - Id = m.Id, - Name = m.Name, - Company = m.Company.Name, - Prototype = m.Prototype - }) - .ToListAsync(); + public Task> GetPrototypesAsync([FromQuery] int? skip = null, [FromQuery] int? take = null, + CancellationToken cancellationToken = default) + { + IQueryable ordered = context.Machines.Include(m => m.Company) + .Where(m => m.Type == MachineType.Smartphone && m.Prototype) + .OrderBy(m => MarechaiContext.NaturalSortKey(m.Company.Name)) + .ThenBy(m => MarechaiContext.NaturalSortKey(m.Name)); + + if(skip.HasValue) ordered = ordered.Skip(skip.Value); + if(take.HasValue) ordered = ordered.Take(take.Value); + + return ordered.Select(m => new MachineDto + { + Id = m.Id, + Name = m.Name, + Company = m.Company.Name, + Prototype = m.Prototype + }) + .ToListAsync(cancellationToken); + } + + [HttpGet("prototypes/count")] + [AllowAnonymous] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public Task GetPrototypesCountAsync(CancellationToken cancellationToken = default) => + context.Machines + .Where(m => m.Type == MachineType.Smartphone && m.Prototype) + .CountAsync(cancellationToken); [HttpGet("companies")] [AllowAnonymous] diff --git a/Marechai/Pages/Smartphones/Search.razor b/Marechai/Pages/Smartphones/Search.razor index a9b0e74c..e9797ef4 100644 --- a/Marechai/Pages/Smartphones/Search.razor +++ b/Marechai/Pages/Smartphones/Search.razor @@ -32,7 +32,7 @@ @inherits OwningComponentBase @inject IStringLocalizer L -@if(_smartphones is null) +@if(!_initialized) {
@@ -56,17 +56,25 @@ } -@if(_smartphones?.Count > 0) +@if(_total > 0) { - @string.Format(L["{0} smartphones found in the database."], _smartphones.Count) - - @foreach(MachineDto smartphone in _smartphones) + @string.Format(L["{0} smartphones found in the database."], _total) +
+ + + + @smartphone.Company @smartphone.Name + + + +
+ @if(_loadingMore) { - - @smartphone.Company @smartphone.Name - +
+ +
} - +
} else { diff --git a/Marechai/Pages/Smartphones/Search.razor.cs b/Marechai/Pages/Smartphones/Search.razor.cs index 7678a763..33c98e35 100644 --- a/Marechai/Pages/Smartphones/Search.razor.cs +++ b/Marechai/Pages/Smartphones/Search.razor.cs @@ -23,21 +23,33 @@ // Copyright © 2003-2026 Natalia Portillo *******************************************************************************/ +using System; using System.Collections.Generic; using System.Threading.Tasks; using Marechai.ApiClient.Models; using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; namespace Marechai.Pages.Smartphones; -public partial class Search +public partial class Search : IAsyncDisposable { - char? _character; - List _smartphones; - bool _loaded; - bool _showPrototypes; - string _lastStartingCharacter; - int? _lastYear; + const int _pageSize = 100; + readonly string _sentinelId = $"smartphones-search-sentinel-{Guid.NewGuid():N}"; + readonly string _scrollerId = $"smartphones-search-scroll-{Guid.NewGuid():N}"; + readonly List _smartphones = []; + char? _character; + bool _initialized; + bool _loadingMore; + bool _observerRegistered; + bool _showPrototypes; + string _lastStartingCharacter; + int? _lastYear; + int _total; + DotNetObjectReference _selfRef; + + [Inject] + IJSRuntime JS { get; set; } [Parameter] public int? Year { get; set; } @@ -45,30 +57,29 @@ public partial class Search [Parameter] public string StartingCharacter { get; set; } + bool HasMore => _smartphones.Count < _total; + protected override void OnParametersSet() { if(Year == _lastYear && StartingCharacter == _lastStartingCharacter) return; _lastYear = Year; _lastStartingCharacter = StartingCharacter; - _loaded = false; + _initialized = false; } protected override async Task OnAfterRenderAsync(bool firstRender) { - if(_loaded) return; - - _character = null; - _showPrototypes = false; - - if(StartingCharacter == "prototypes") + if(!_initialized) { - _showPrototypes = true; - _smartphones = await Service.GetPrototypesAsync(); - } - else - { - if(!string.IsNullOrWhiteSpace(StartingCharacter) && StartingCharacter.Length == 1) + _character = null; + _showPrototypes = false; + _total = 0; + _smartphones.Clear(); + + if(StartingCharacter == "prototypes") + _showPrototypes = true; + else if(!string.IsNullOrWhiteSpace(StartingCharacter) && StartingCharacter.Length == 1) { _character = StartingCharacter[0]; @@ -79,14 +90,117 @@ public partial class Search if(_character < '0' || _character > '9' && _character < 'A' || _character > 'Z') _character = null; } - if(_character.HasValue) _smartphones = await Service.GetSmartphonesByLetterAsync(_character.Value); + // Stop the previous observer (if any) before swapping in a new + // batch — the sentinel/scroller IDs are stable per page instance, + // but a route-parameter change forces a fresh data load and the + // observer must be re-armed once the new sentinel has rendered. + await UnobserveAsync(); - if(Year.HasValue && _smartphones is null) _smartphones = await Service.GetSmartphonesByYearAsync(Year.Value); + // Fetch the total count + first page in parallel so the page is + // fully painted in one round-trip pair. + Task countTask = GetCurrentCountAsync(); + Task> firstPageTask = FetchBatchAsync(0, _pageSize); - _smartphones ??= await Service.GetSmartphonesAsync(); + await Task.WhenAll(countTask, firstPageTask); + + _total = countTask.Result; + _smartphones.AddRange(firstPageTask.Result); + _initialized = true; + + StateHasChanged(); + return; } - _loaded = true; + // Register the IntersectionObserver once the sentinel has been + // rendered. The observer keeps the same target reference, so this is + // a one-shot until UnobserveAsync clears the flag. + if(!_observerRegistered && HasMore) + { + _selfRef ??= DotNetObjectReference.Create(this); + + try + { + await JS.InvokeVoidAsync("marechaiInfiniteScroll.observe", _sentinelId, _selfRef, $"#{_scrollerId}", + "200px"); + _observerRegistered = true; + } + catch(JSDisconnectedException) + { + // Circuit gone — nothing to do. + } + } + } + + /// + /// Invoked by the IntersectionObserver in infinite-scroll.js when the + /// sentinel scrolls into view. Loads the next page, appends it to the + /// in-memory list, and re-renders. + /// + [JSInvokable] + public async Task OnSentinelVisibleAsync() + { + if(_loadingMore || !HasMore) return; + + _loadingMore = true; StateHasChanged(); + + try + { + List next = await FetchBatchAsync(_smartphones.Count, _pageSize); + _smartphones.AddRange(next); + + // If the very last page just arrived, stop the observer so it + // doesn't keep firing as the user scrolls past the new tail. + if(!HasMore) await UnobserveAsync(); + } + finally + { + _loadingMore = false; + StateHasChanged(); + } + } + + Task GetCurrentCountAsync() + { + if(_showPrototypes) return Service.GetPrototypesCountAsync(); + + if(_character.HasValue) return Service.GetSmartphonesByLetterCountAsync(_character.Value); + + if(Year.HasValue) return Service.GetSmartphonesByYearCountAsync(Year.Value); + + return Service.GetSmartphonesCountAsync(); + } + + Task> FetchBatchAsync(int skip, int take) + { + if(_showPrototypes) return Service.GetPrototypesAsync(skip, take); + + if(_character.HasValue) return Service.GetSmartphonesByLetterAsync(_character.Value, skip, take); + + if(Year.HasValue) return Service.GetSmartphonesByYearAsync(Year.Value, skip, take); + + return Service.GetSmartphonesAsync(skip, take); + } + + async Task UnobserveAsync() + { + if(!_observerRegistered) return; + + try + { + await JS.InvokeVoidAsync("marechaiInfiniteScroll.unobserve", _sentinelId); + } + catch(JSDisconnectedException) + { + // Circuit gone; nothing to do. + } + + _observerRegistered = false; + } + + public async ValueTask DisposeAsync() + { + await UnobserveAsync(); + _selfRef?.Dispose(); } } diff --git a/Marechai/Services/SmartphonesService.cs b/Marechai/Services/SmartphonesService.cs index ae2dcdc1..9720177e 100644 --- a/Marechai/Services/SmartphonesService.cs +++ b/Marechai/Services/SmartphonesService.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Marechai.ApiClient.Models; @@ -74,11 +75,16 @@ public class SmartphonesService(Marechai.ApiClient.Client client) } } - public async Task> GetSmartphonesByLetterAsync(char c) + public async Task> GetSmartphonesByLetterAsync(char c, int? skip = null, int? take = null, + CancellationToken cancellationToken = default) { try { - List machines = await client.Smartphones.ByLetter[c.ToString()].GetAsync(); + List machines = await client.Smartphones.ByLetter[c.ToString()].GetAsync(config => + { + if(skip.HasValue) config.QueryParameters.Skip = skip.Value; + if(take.HasValue) config.QueryParameters.Take = take.Value; + }, cancellationToken); return machines ?? []; } @@ -88,11 +94,31 @@ public class SmartphonesService(Marechai.ApiClient.Client client) } } - public async Task> GetSmartphonesByYearAsync(int year) + public async Task GetSmartphonesByLetterCountAsync(char c, CancellationToken cancellationToken = default) { try { - List machines = await client.Smartphones.ByYear[year].GetAsync(); + int? count = await client.Smartphones.ByLetter[c.ToString()].Count + .GetAsync(cancellationToken: cancellationToken); + + return count ?? 0; + } + catch + { + return 0; + } + } + + public async Task> GetSmartphonesByYearAsync(int year, int? skip = null, int? take = null, + CancellationToken cancellationToken = default) + { + try + { + List machines = await client.Smartphones.ByYear[year].GetAsync(config => + { + if(skip.HasValue) config.QueryParameters.Skip = skip.Value; + if(take.HasValue) config.QueryParameters.Take = take.Value; + }, cancellationToken); return machines ?? []; } @@ -102,11 +128,30 @@ public class SmartphonesService(Marechai.ApiClient.Client client) } } - public async Task> GetSmartphonesAsync() + public async Task GetSmartphonesByYearCountAsync(int year, CancellationToken cancellationToken = default) { try { - List machines = await client.Smartphones.GetAsync(); + int? count = await client.Smartphones.ByYear[year].Count.GetAsync(cancellationToken: cancellationToken); + + return count ?? 0; + } + catch + { + return 0; + } + } + + public async Task> GetSmartphonesAsync(int? skip = null, int? take = null, + CancellationToken cancellationToken = default) + { + try + { + List machines = await client.Smartphones.GetAsync(config => + { + if(skip.HasValue) config.QueryParameters.Skip = skip.Value; + if(take.HasValue) config.QueryParameters.Take = take.Value; + }, cancellationToken); return machines ?? []; } @@ -116,11 +161,16 @@ public class SmartphonesService(Marechai.ApiClient.Client client) } } - public async Task> GetPrototypesAsync() + public async Task> GetPrototypesAsync(int? skip = null, int? take = null, + CancellationToken cancellationToken = default) { try { - List machines = await client.Smartphones.Prototypes.GetAsync(); + List machines = await client.Smartphones.Prototypes.GetAsync(config => + { + if(skip.HasValue) config.QueryParameters.Skip = skip.Value; + if(take.HasValue) config.QueryParameters.Take = take.Value; + }, cancellationToken); return machines ?? []; } @@ -130,6 +180,20 @@ public class SmartphonesService(Marechai.ApiClient.Client client) } } + public async Task GetPrototypesCountAsync(CancellationToken cancellationToken = default) + { + try + { + int? count = await client.Smartphones.Prototypes.Count.GetAsync(cancellationToken: cancellationToken); + + return count ?? 0; + } + catch + { + return 0; + } + } + public async Task> GetCompaniesAsync() { try