Skip to content

Conversation

ReneWerner87
Copy link
Member

@ReneWerner87 ReneWerner87 commented Aug 21, 2025

Summary

  • raise module and CI to Go 1.25
  • replace direct type assertions with reflect.TypeAssert

Testing

  • go test ./...

https://chatgpt.com/codex/tasks/task_e_68a6f89e1c2c8326b880eb6f82f058b8

Summary by CodeRabbit

  • Refactor

    • Standardized type handling using a generic helper across decoding and encoding paths for improved consistency and maintainability.
    • Preserves existing behavior and public APIs; no user-facing changes expected.
  • Tests

    • Updated tests and benchmarks to align with the new generic type handling approach.
    • Ensures coverage remains equivalent with no changes to expected outcomes.

@ReneWerner87 ReneWerner87 requested a review from a team as a code owner August 21, 2025 11:10
@ReneWerner87 ReneWerner87 requested review from gaby, sixcolors and efectn and removed request for a team August 21, 2025 11:10
Copy link

coderabbitai bot commented Aug 21, 2025

Walkthrough

Refactors type assertions to use a generic reflective helper reflect.TypeAssert across decoder, encoder, and tests. Decoder and tests replace direct interface assertions with TypeAssert. Encoder’s isZero retrieves the IsZero() bool result via TypeAssert on a reflect.Value return. No public APIs changed.

Changes

Cohort / File(s) Summary of Changes
Decoder: TextUnmarshaler via TypeAssert
decoder.go
Replaced direct encoding.TextUnmarshaler assertions with reflect.TypeAssert throughout decode paths and isTextUnmarshaler; preserved control flow and error handling semantics; initialized Unmarshaler fields via TypeAssert.
Encoder: isZero bool extraction
encoder.go
In isZero, replaced direct bool assertion from MethodByName("IsZero").Call(...) with reflect.TypeAssertbool. Discards the ok flag; returns the asserted (or zero) bool. Other logic unchanged.
Tests/Benchmarks: Assertion helper adoption
encoder_test.go
Swapped value.Interface().(T) style assertions for reflect.TypeAssertT across multiple tests/benchmarks (time.Time, *CustomTime, time.Duration); ignored ok flag; behavior otherwise unchanged.

Sequence Diagram(s)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A bunny taps the keys with cheer,
TypeAssert hops in, crystal clear.
Encoders, decoders, all align,
Reflection burrows look quite fine.
Tests now nibble simpler fare—
Less casting carrots, more fresh air. 🥕🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/2025-08-21-11-10-50

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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 or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @ReneWerner87, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on a maintenance update and a code refactoring effort. It upgrades the project's Go version to 1.25, ensuring compatibility with the latest language features and improvements. Concurrently, it modernizes the codebase by replacing traditional interface{}.(Type) type assertions with reflect.TypeAssert where reflect.Value is involved, enhancing type safety and leveraging newer Go reflection capabilities.

Highlights

  • Go Version Upgrade: The Go module and continuous integration (CI) configuration have been updated to utilize Go version 1.25, aligning the project with the latest stable release.
  • Type Assertion Refactoring: Direct type assertions using value.Interface().(Type) have been systematically replaced with the more modern and type-safe reflect.TypeAssert function across decoder.go and encoder_test.go. This change leverages Go's generics to provide compile-time type checking for reflection-based assertions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

codecov bot commented Aug 21, 2025

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 95.98%. Comparing base (ffee63d) to head (0fb7bab).

Files with missing lines Patch % Lines
decoder.go 88.88% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main      #35   +/-   ##
=======================================
  Coverage   95.97%   95.98%           
=======================================
  Files           4        4           
  Lines         945      947    +2     
=======================================
+ Hits          907      909    +2     
  Misses         27       27           
  Partials       11       11           
Flag Coverage Δ
unittests 95.98% <90.90%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is a great initiative to modernize the codebase by upgrading to Go 1.25 and adopting reflect.TypeAssert. The changes are generally in the right direction. However, there's a recurring issue with how reflect.TypeAssert is used. The boolean ok it returns is consistently ignored. This is problematic because reflect.TypeAssert is equivalent to a two-value type assertion (val, ok := i.(T)), which doesn't panic on failure but returns a zero value and ok=false. The original code used single-value assertions (i.(T)) which panic on failure. By ignoring ok, the new code can lead to nil-pointer dereference panics or, worse, silent bugs where an unexpected zero value is used. My review comments focus on correcting this pattern to ensure the code is robust and behaves as expected.

u = reflect.New(reflect.PointerTo(elemT).Elem())
}
if err := u.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
um, _ := reflect.TypeAssert[encoding.TextUnmarshaler](u)

Choose a reason for hiding this comment

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

high

Ignoring the ok boolean from reflect.TypeAssert is unsafe. If the type assertion fails, um will be nil, and the subsequent call to um.UnmarshalText will cause a nil-pointer dereference panic. While the original code also panicked on a failed assertion, relying on a nil-dereference is less clear and is considered an anti-pattern. It's much safer to explicitly check the ok value and handle the failure. Since the original code would panic, preserving that behavior is best to signal an internal error.

if m.IsPtr {
u := reflect.New(v.Type())
if err := u.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(val)); err != nil {
um, _ := reflect.TypeAssert[encoding.TextUnmarshaler](u)

Choose a reason for hiding this comment

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

high

Similar to the previous comment, the ok boolean returned by reflect.TypeAssert is being ignored. This can lead to a nil-pointer dereference panic if the assertion fails. Please check the ok value to handle the failed assertion explicitly. This makes the code safer and the intent clearer.

Comment on lines +64 to +65
iz, _ := reflect.TypeAssert[bool](v.MethodByName("IsZero").Call([]reflect.Value{})[0])
return iz

Choose a reason for hiding this comment

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

high

Ignoring the ok boolean from reflect.TypeAssert changes the behavior of the function. The original code would panic if the type assertion failed. The new code will instead assign the zero value for bool (which is false) to iz and return it. This masks a potential error and leads to incorrect behavior. The ok value should be checked to ensure the assertion was successful, and you should panic on failure to maintain the original contract of this function.

Suggested change
iz, _ := reflect.TypeAssert[bool](v.MethodByName("IsZero").Call([]reflect.Value{})[0])
return iz
izValue := v.MethodByName("IsZero").Call([]reflect.Value{})[0]
if iz, ok := reflect.TypeAssert[bool](izValue); ok {
return iz
}
panic("schema: IsZero() returned a non-boolean value")

Comment on lines +474 to +475
tv, _ := reflect.TypeAssert[time.Time](value)
return tv.Format(time.RFC3339Nano)

Choose a reason for hiding this comment

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

high

By ignoring the ok boolean from reflect.TypeAssert, you're introducing a potential bug. If the type assertion fails, tv will be a zero time.Time, and the function will return a formatted zero-time string instead of panicking like the original code did. This can hide issues. Please check the ok value and panic on failure to preserve the original behavior.

if tv, ok := reflect.TypeAssert[time.Time](value); ok {
    return tv.Format(time.RFC3339Nano)
}
panic("schema: encoder for time.Time received an unexpected type")

Comment on lines +525 to 526
custom, _ := reflect.TypeAssert[*CustomTime](value)
return custom.time.String()

Choose a reason for hiding this comment

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

high

Ignoring the ok boolean from reflect.TypeAssert makes the code rely on a subsequent nil-pointer dereference to panic, which is less explicit than panicking on a failed assertion. While the behavior is similar to the original code, it's better practice to check the ok value and handle the failure case directly.

if custom, ok := reflect.TypeAssert[*CustomTime](value); ok {
    return custom.time.String()
}
panic("schema: encoder for *CustomTime received an unexpected type")

Comment on lines +550 to 551
d, _ := reflect.TypeAssert[time.Duration](v)
return d.String() // "3m0s"

Choose a reason for hiding this comment

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

high

The ok boolean from reflect.TypeAssert is ignored here. If the assertion fails, d will be the zero value for time.Duration (0), and d.String() will return "0s". The original code would have panicked. This change in behavior can hide bugs. Please check the ok value and panic on failure.

if d, ok := reflect.TypeAssert[time.Duration](v); ok {
    return d.String() // "3m0s"
}
panic("schema: encoder for time.Duration received an unexpected type")

Comment on lines +581 to +582
d, _ := reflect.TypeAssert[time.Duration](v)
return d.String()

Choose a reason for hiding this comment

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

high

The ok boolean from reflect.TypeAssert is ignored. If the assertion fails, this function will return "0s" (the string representation of a zero time.Duration) instead of panicking as the original code did. This can mask errors. It's important to check the ok value.

if d, ok := reflect.TypeAssert[time.Duration](v); ok {
    return d.String()
}
panic("schema: encoder for time.Duration received an unexpected type")

Comment on lines +736 to 737
tVal, _ := reflect.TypeAssert[time.Time](v)
return tVal.Format(time.RFC3339)

Choose a reason for hiding this comment

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

high

Ignoring the ok boolean from reflect.TypeAssert can lead to silent errors. If the assertion fails, a formatted zero-time string will be returned instead of panicking, which was the behavior of the original code. Please check the ok value to ensure the code is robust.

if tVal, ok := reflect.TypeAssert[time.Time](v); ok {
    return tVal.Format(time.RFC3339)
}
panic("schema: encoder for time.Time received an unexpected type")

Comment on lines +762 to 763
tVal, _ := reflect.TypeAssert[time.Time](v)
return tVal.Format(time.RFC3339)

Choose a reason for hiding this comment

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

high

As with other instances in this PR, the ok boolean from reflect.TypeAssert is being ignored. This can cause the function to return an incorrect value (a formatted zero-time string) if the type assertion fails, whereas the original code would have panicked. Please check the ok value.

if tVal, ok := reflect.TypeAssert[time.Time](v); ok {
    return tVal.Format(time.RFC3339)
}
panic("schema: encoder for time.Time received an unexpected type")

Comment on lines +786 to +787
d, _ := reflect.TypeAssert[time.Duration](v)
return d.String()

Choose a reason for hiding this comment

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

high

The ok boolean from reflect.TypeAssert is ignored. This can lead to incorrect behavior (returning "0s") if the type assertion fails, while the original code would have panicked. Please check the ok value to maintain correctness and robustness.

if d, ok := reflect.TypeAssert[time.Duration](v); ok {
    return d.String()
}
panic("schema: encoder for time.Duration received an unexpected type")

Copy link

@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)
encoder_test.go (1)

474-476: Tests: solid migration to reflect.TypeAssert; consider asserting the ok for clearer failures.

Using reflect.TypeAssert in tests removes Interface() allocations and mirrors production paths. For even clearer diagnostics when a registration accidentally passes the wrong type, consider checking ok and failing fast with a descriptive message (small nit, since these sites are expected to succeed).

Example pattern you can apply to these sites:

- tv, _ := reflect.TypeAssert[time.Time](value)
- return tv.Format(time.RFC3339Nano)
+ if tv, ok := reflect.TypeAssert[time.Time](value); ok {
+   return tv.Format(time.RFC3339Nano)
+ }
+ t.Fatalf("internal: expected time.Time, got %v", value.Type())
+ return ""

And similarly for:

  • line 525: *CustomTime
  • lines 549/580/786: time.Duration
  • lines 736/762: time.Time

Note: reflect.TypeAssert is available starting in Go 1.25. (tip.golang.org)

Also applies to: 525-526, 549-552, 580-583, 736-738, 762-764, 786-788

decoder.go (2)

496-498: Use the ok result from TypeAssert to avoid a potential nil-interface method call.

In the unlikely event m.IsValid is out of sync with the actual value, um would be a typed-nil interface and calling UnmarshalText would panic. Guarding with ok provides a safer, clearer error.

Apply:

-        um, _ := reflect.TypeAssert[encoding.TextUnmarshaler](u)
-        if err := um.UnmarshalText([]byte(value)); err != nil {
+        um, ok := reflect.TypeAssert[encoding.TextUnmarshaler](u)
+        if !ok {
+          return ConversionError{
+            Key:   path, Type: t, Index: key,
+            Err:   fmt.Errorf("expected %v to implement encoding.TextUnmarshaler", u.Type()),
+          }
+        }
+        if err := um.UnmarshalText([]byte(value)); err != nil {

579-581: Mirror the TypeAssert ok check on the non-slice path for consistency and safety.

Same reasoning as above; this avoids a panic path and returns a structured ConversionError instead.

-        um, _ := reflect.TypeAssert[encoding.TextUnmarshaler](u)
-        if err := um.UnmarshalText([]byte(val)); err != nil {
+        if um, ok := reflect.TypeAssert[encoding.TextUnmarshaler](u); ok {
+          if err := um.UnmarshalText([]byte(val)); err != nil {
             return ConversionError{
               Key:   path,
               Type:  t,
               Index: -1,
               Err:   err,
             }
-        }
+          }
+        } else {
+          return ConversionError{
+            Key:   path, Type: t, Index: -1,
+            Err:   fmt.Errorf("expected %v to implement encoding.TextUnmarshaler", u.Type()),
+          }
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ffee63d and 0fb7bab.

⛔ Files ignored due to path filters (4)
  • .github/workflows/benchmark.yml is excluded by !**/*.yml
  • .github/workflows/linter.yml is excluded by !**/*.yml
  • .github/workflows/test.yml is excluded by !**/*.yml
  • go.mod is excluded by !**/*.mod
📒 Files selected for processing (3)
  • decoder.go (5 hunks)
  • encoder.go (1 hunks)
  • encoder_test.go (7 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-07-26T21:00:12.902Z
Learning: The project uses the testify/assert package for assertions in unit tests.
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The project uses the testify/assert package for assertions in unit tests.
📚 Learning: 2024-07-01T15:49:51.308Z
Learnt from: luk3skyw4lker
PR: gofiber/storage#1342
File: clickhouse/clickhouse.go:106-107
Timestamp: 2024-07-01T15:49:51.308Z
Learning: The `IsZero` function for `time.Time` structs in the ClickHouse storage driver was returning false even for zero value `time.Time` structs. As a result, a different verification logic was implemented to avoid bugs.

Applied to files:

  • encoder.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: unit (1.25.x, macos-13)
  • GitHub Check: unit (1.25.x, windows-latest)
🔇 Additional comments (2)
encoder.go (1)

64-65: Please verify Go version enforcement

I wasn’t able to locate any go.mod or go.work file in the repository, nor any GitHub Actions workflows under .github/workflows, so it’s unclear whether CI or local builds are pinned to Go 1.25 or newer. Before merging, please confirm that:

  • A go.mod or go.work at the project root specifies go 1.25 (or higher).
  • All CI pipelines (e.g. GitHub Actions, other runners) are configured to use Go 1.25+.

This ensures the use of reflect.TypeAssert (introduced in Go 1.25) will work reliably both locally and on CI.

decoder.go (1)

625-626: LGTM: centralizing interface checks on reflect.TypeAssert reduces allocations and simplifies isTextUnmarshaler.

This refactor is faithful to the original logic while leveraging the new stdlib helper; it should be a net win for hot decode paths that hit TextUnmarshaler frequently. (tip.golang.org)

Also applies to: 632-632, 644-644, 654-654, 660-660

@ReneWerner87
Copy link
Member Author

@gofiber/maintainers pls review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant