Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(graphql): Add missing search parameters for paging and sorting #1671

Conversation

oskogstad
Copy link
Collaborator

Description

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)

Documentation

  • Documentation is updated (either in docs-directory, Altinnpedia or a separate linked PR in altinn-studio-docs., if applicable)

Copy link
Contributor

coderabbitai bot commented Jan 9, 2025

Warning

Rate limit exceeded

@oskogstad has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 12 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 2be2939 and 981b8c9.

📒 Files selected for processing (2)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogQueries.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/SearchDialogSortTypeExtensions.cs (1 hunks)
📝 Walkthrough

Walkthrough

This pull request introduces enhancements to the GraphQL schema and related components for search functionality in dialogs, focusing on improved error handling, sorting, and pagination capabilities. Key changes include the addition of new types for error handling and sorting, modifications to existing payload and input types, and updates to the query handling logic to incorporate validation and parsing for continuation tokens and order criteria.

Changes

File Change Summary
docs/schema/V1/schema.verified.graphql - Added SearchDialogContinuationTokenParsingError and SearchDialogOrderByParsingError types
- Introduced SearchDialogSortType and SearchDialogSortTypeInput types
- Modified SearchDialogsPayload to support multiple sorting criteria and added continuationToken field
- Updated SearchDialogInput to include limit and continuationToken fields
- Added OrderDirection enum
src/Digdir.Domain.Dialogporten.Application/.../IPaginationParameter.cs - Changed ContinuationToken and OrderBy properties from init to set accessors
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogQueries.cs - Enhanced SearchDialogs method with validation and error handling for continuation tokens and order parsing
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/MappingProfile.cs - Updated mapping configurations to ignore specific properties during mapping
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs - Added SearchDialogContinuationTokenParsingError and SearchDialogOrderByParsingError classes
- Created SearchDialogSortType and OrderDirection enum
- Updated SearchDialogsPayload and SearchDialogInput types
src/Digdir.Domain.Dialogporten.GraphQL/Digdir.Domain.Dialogporten.GraphQL.csproj - Added package reference for AppAny.HotChocolate.FluentValidation
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/SearchDialogInputValidator.cs - Introduced SearchDialogInputValidator for validating SearchDialogInput
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/SearchDialogSortTypeExtensions.cs - Added extension methods for converting and handling sorting logic
src/Digdir.Domain.Dialogporten.GraphQL/ServiceCollectionExtensions.cs - Enhanced AddDialogportenGraphQl method to include FluentValidation and register new error types

Possibly related PRs

Suggested reviewers

  • MagnusSandgren
  • arealmaas

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

sonarqubecloud bot commented Jan 9, 2025

@oskogstad oskogstad force-pushed the fix/gql-add-missing-search-parameters-for-pagination-orderby-limit branch from 019ca1f to ff335b7 Compare January 13, 2025 14:40
@oskogstad oskogstad marked this pull request as ready for review January 14, 2025 12:40
@oskogstad oskogstad requested a review from a team as a code owner January 14, 2025 12:40
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (8)
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogQueries.cs (1)

43-52: Consider localizing the error message for OrderBy parsing.

The error handling for OrderBy parsing is robust, but the error message is hardcoded in SearchDialogOrderByParsingError. Consider making error messages localizable for better internationalization support.

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs (3)

159-165: Consider throwing an exception for invalid OrderBy format.

The current implementation silently ignores invalid parts in the OrderBy string. This could mask configuration errors and make debugging more difficult.

 foreach (var orderByPart in orderBy.Split(','))
 {
     var parts = orderByPart.Split('_');
     if (parts.Length != 2)
     {
-        continue;
+        throw new FormatException($"Invalid OrderBy format: {orderByPart}. Expected format: field_direction");
     }

154-157: Optimize string replacements using StringComparison.OrdinalIgnoreCase.

The string replacements for 'id_desc' and 'id_asc' are using StringComparison.OrdinalIgnoreCase inconsistently. Consider using it for ToLower as well:

-orderBy = orderBy
-    .ToLower(CultureInfo.InvariantCulture)
+orderBy = orderBy.ToLowerInvariant()
     .Replace("id_desc", "", StringComparison.OrdinalIgnoreCase)
     .Replace("id_asc", "", StringComparison.OrdinalIgnoreCase);

189-206: Optimize StringBuilder usage in TryToOrderSet.

The current implementation appends to StringBuilder in a conditional manner, which could be simplified. Also, consider pre-allocating the StringBuilder capacity based on the expected size.

-var stringBuilder = new StringBuilder();
+var stringBuilder = new StringBuilder(searchDialogSortTypes.Count * 20); // Estimate 20 chars per sort type
 foreach (var orderBy in searchDialogSortTypes)
 {
-    if (orderBy.CreatedAt != null)
-    {
-        stringBuilder.Append(CultureInfo.InvariantCulture, $"createdAt_{orderBy.CreatedAt},");
-        continue;
-    }
-    if (orderBy.UpdatedAt != null)
-    {
-        stringBuilder.Append(CultureInfo.InvariantCulture, $"updatedAt_{orderBy.UpdatedAt},");
-        continue;
-    }
-    if (orderBy.DueAt != null)
-    {
-        stringBuilder.Append(CultureInfo.InvariantCulture, $"dueAt_{orderBy.DueAt},");
-    }
+    var (field, direction) = orderBy switch
+    {
+        { CreatedAt: not null } => ("createdAt", orderBy.CreatedAt),
+        { UpdatedAt: not null } => ("updatedAt", orderBy.UpdatedAt),
+        { DueAt: not null } => ("dueAt", orderBy.DueAt),
+        _ => continue
+    };
+    stringBuilder.Append(CultureInfo.InvariantCulture, $"{field}_{direction},");
 }
docs/schema/V1/schema.verified.graphql (4)

218-223: Enhance the description for better clarity.

The description should be more explicit about the behavior when multiple sort fields are set. Consider clarifying whether fields are applied in order of appearance and what the default sort direction is when none is specified.

-"Set only one property per object. If more than one property is set, there is no guarantee which one will be used."
+"Set only one property per object. Multiple properties will result in undefined sorting behavior. When specified, properties should use ASC or DESC direction, defaulting to ASC if not specified."

232-235: LGTM! Consider adding pagination examples to documentation.

The implementation follows the cursor-based pagination pattern correctly. The non-nullable orderBy field ensures consistent pagination results.

Consider adding examples in the documentation showing how to use continuationToken with orderBy for pagination, as this pattern might be new to some API consumers.


308-309: Add schema-level constraints for the limit field.

While the description specifies the default and maximum values for limit, consider adding schema-level constraints using @constraint directive to enforce these limits.

"Limit the number of results returned"
limit: Int @constraint(min: 1, max: 1000)

411-414: Add descriptions for the SortDirection enum.

Consider adding descriptions to improve schema documentation:

+"""
+Specifies the sort order for query results
+"""
 enum SortDirection {
+  "Sort in ascending order"
   ASC
+  "Sort in descending order"
   DESC
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a0697ae and 4459b0c.

📒 Files selected for processing (5)
  • docs/schema/V1/schema.verified.graphql (3 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Common/Pagination/IPaginationParameter.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogQueries.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/MappingProfile.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs (4 hunks)
🔇 Additional comments (7)
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/MappingProfile.cs (1)

12-13: LGTM! Appropriate mapping configuration for pagination and sorting.

The explicit ignore configurations for OrderBy and ContinuationToken properties are correct, as these properties require special handling in the query execution phase.

Also applies to: 16-17

src/Digdir.Domain.Dialogporten.Application/Common/Pagination/IPaginationParameter.cs (1)

13-13: Consider the implications of mutable pagination properties.

Changing ContinuationToken and OrderBy from init to set makes these properties mutable after object construction. While this enables the new pagination and sorting functionality, it could lead to unexpected behavior if these properties are modified during the object's lifecycle.

Consider:

  1. Documenting the intended usage pattern
  2. Adding validation when these properties are modified
  3. Implementing immutable alternatives if possible

Also applies to: 25-25

✅ Verification successful

Property mutability is justified and well-controlled

The mutable properties are used appropriately within the pagination workflow, with modifications occurring only during query execution, token management, and result mapping. The implementation follows standard patterns for GraphQL pagination.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any direct modifications to these properties outside of the initial setup
rg -A 3 "ContinuationToken\s*=\s*" --type cs
rg -A 3 "OrderBy\s*=\s*" --type cs

Length of output: 2778

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogQueries.cs (2)

37-41: LGTM! Robust continuation token handling.

The implementation correctly parses and validates the continuation token before applying it to the query.


57-62: LGTM! Clean mapping with order preservation.

The implementation correctly preserves the ordering information in the mapped result.

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs (2)

45-51: LGTM! Well-structured sort type definition.

The SearchDialogSortType class with its GraphQL description and nullable direction properties provides a clean and self-documenting API for sort operations.


137-144: LGTM! Clear pagination and sorting parameters.

The input parameters for limit, continuation token, and ordering are well-documented with GraphQL descriptions and have appropriate nullable types.

docs/schema/V1/schema.verified.graphql (1)

316-320: LGTM! Input type correctly mirrors the sort type.

The implementation follows GraphQL best practices by using a separate input type for mutations/queries.

oskogstad and others added 2 commits January 16, 2025 00:47
Co-authored-by: Ole Jørgen Skogstad <skogstad@softis.net>
MagnusSandgren
MagnusSandgren previously approved these changes Jan 16, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/SearchDialogSortTypeExtensions.cs (3)

11-45: Consider using constants for field names.

While the implementation is efficient using span operations, consider extracting the field names into constants to improve maintainability and reduce the risk of typos.

 internal static class SearchDialogSortTypeExtensions
 {
+    private const string CreatedAtField = "createdat";
+    private const string UpdatedAtField = "updatedat";
+    private const string DueAtField = "dueat";
+
     public static List<SearchDialogSortType> ToSearchDialogSortTypeList(this ReadOnlySpan<char> orderSet)

47-80: Consider extracting a helper method to reduce duplication.

The string building logic for each field follows the same pattern. Consider extracting it to a helper method to reduce duplication.

+    private static void AppendOrderBy(StringBuilder sb, string field, OrderDirection? direction)
+    {
+        if (direction.HasValue)
+        {
+            sb.Append(CultureInfo.InvariantCulture, $"{field}_{direction},");
+        }
+    }
+
     public static bool TryToOrderSet(this List<SearchDialogSortType> searchDialogSortTypes,
         out OrderSet<SearchDialogQueryOrderDefinition, IntermediateDialogDto>? orderSet)
     {
         var stringBuilder = new StringBuilder();
         foreach (var orderBy in searchDialogSortTypes)
         {
-            if (orderBy.CreatedAt.HasValue)
-            {
-                stringBuilder.Append(CultureInfo.InvariantCulture, $"createdAt_{orderBy.CreatedAt},");
-                continue;
-            }
-
-            if (orderBy.UpdatedAt.HasValue)
-            {
-                stringBuilder.Append(CultureInfo.InvariantCulture, $"updatedAt_{orderBy.UpdatedAt},");
-                continue;
-            }
-
-            if (orderBy.DueAt.HasValue)
-            {
-                stringBuilder.Append(CultureInfo.InvariantCulture, $"dueAt_{orderBy.DueAt},");
-            }
+            AppendOrderBy(stringBuilder, "createdAt", orderBy.CreatedAt);
+            AppendOrderBy(stringBuilder, "updatedAt", orderBy.UpdatedAt);
+            AppendOrderBy(stringBuilder, "dueAt", orderBy.DueAt);
         }

82-100: Consider using a switch expression for better readability.

The if-else chain could be replaced with a more concise switch expression.

     private static Func<OrderDirection, SearchDialogSortType> GetSearchDialogSortTypeFactory(ReadOnlySpan<char> field)
-    {
-        if (field.Equals("createdat", StringComparison.OrdinalIgnoreCase))
-        {
-            return CreatedAtFactory;
-        }
-
-        if (field.Equals("updatedat", StringComparison.OrdinalIgnoreCase))
-        {
-            return UpdatedAtFactory;
-        }
-
-        if (field.Equals("dueat", StringComparison.OrdinalIgnoreCase))
-        {
-            return DuAtFactory;
-        }
-
-        throw new InvalidOperationException("Invalid sort field");
-    }
+        => field.ToString().ToLowerInvariant() switch
+        {
+            "createdat" => CreatedAtFactory,
+            "updatedat" => UpdatedAtFactory,
+            "dueat" => DuAtFactory,
+            _ => throw new InvalidOperationException("Invalid sort field")
+        };
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f50c36 and 2be2939.

📒 Files selected for processing (4)
  • docs/schema/V1/schema.verified.graphql (3 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogQueries.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs (4 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/SearchDialogSortTypeExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/schema/V1/schema.verified.graphql
🔇 Additional comments (11)
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/DialogQueries.cs (4)

33-33: LGTM! Good addition of input validation.

Adding FluentValidation ensures that the input is validated before processing, which is a good practice for maintaining data integrity.


39-49: LGTM! Good error handling for continuation token.

The code properly handles the case where continuation token parsing fails, returning a clear error message. The early return pattern makes the code flow easy to follow.


51-60: LGTM! Good error handling for order set.

The code properly handles the case where order set parsing fails, returning a clear error message. The early return pattern makes the code flow easy to follow.


65-70: LGTM! Good use of Span for performance.

The code efficiently maps the paginated list to the payload, and uses Span operations for better performance when mapping the order by field.

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/SearchDialogSortTypeExtensions.cs (1)

102-104: LGTM! Clear and concise factory methods.

The factory methods are well-named and follow a consistent pattern.

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/SearchDialogs/ObjectTypes.cs (6)

13-21: LGTM! Clear error messages and consistent implementation.

The new error classes follow the established pattern and provide clear error messages.


37-41: LGTM! Good documentation and null safety.

The GraphQL description for ContinuationToken is clear and helpful. The OrderBy property is properly initialized to prevent null reference exceptions.


46-52: Add validation for sort type properties.

While the GraphQL description indicates that only one property should be set per object, this isn't enforced by code.


129-129: LGTM! Accurate language code example.

The description now uses the correct ISO 639 language code example ('nb' instead of 'no').


132-133: Add validation for the Limit property.

While the GraphQL description specifies defaults and constraints for the Limit property, these aren't enforced by code.


135-139: LGTM! Clear documentation for pagination and sorting.

The GraphQL descriptions for ContinuationToken and OrderBy are clear and helpful, properly documenting the pagination and sorting capabilities.

@oskogstad oskogstad force-pushed the fix/gql-add-missing-search-parameters-for-pagination-orderby-limit branch from 1f79e87 to 8cb5a02 Compare January 16, 2025 12:09
@oskogstad oskogstad force-pushed the fix/gql-add-missing-search-parameters-for-pagination-orderby-limit branch from 8cb5a02 to 429d059 Compare January 16, 2025 12:10
@oskogstad oskogstad merged commit 02f2335 into main Jan 17, 2025
23 checks passed
@oskogstad oskogstad deleted the fix/gql-add-missing-search-parameters-for-pagination-orderby-limit branch January 17, 2025 09:29
@coderabbitai coderabbitai bot mentioned this pull request Jan 17, 2025
4 tasks
knuhau pushed a commit that referenced this pull request Jan 18, 2025
🤖 I have created a release *beep* *boop*
---


##
[1.45.1](v1.45.0...v1.45.1)
(2025-01-18)


### Bug Fixes

* **graphql:** Add missing search parameters for paging and sorting
([#1671](#1671))
([02f2335](02f2335))
* Removed .AsSingleQuery from EndUser Search query
([#1707](#1707))
([2a3153b](2a3153b))
* **webapi:** Use correct language code for norwegian in OpenApi
description
([#1705](#1705))
([ce0a07d](ce0a07d))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
This was referenced Jan 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants