Skip to content

fix(dynamo-gen): filter [UnixTimestamp] to DateTime/DateTimeOffset properties#74

Merged
Im5tu merged 3 commits into
mainfrom
fix/dynamo-unixtimestamp-filtering
Jun 18, 2026
Merged

fix(dynamo-gen): filter [UnixTimestamp] to DateTime/DateTimeOffset properties#74
Im5tu merged 3 commits into
mainfrom
fix/dynamo-unixtimestamp-filtering

Conversation

@Im5tu

@Im5tu Im5tu commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • [UnixTimestamp] applied to an incompatible property type (e.g. a long TTL) is now filtered out during attribute processing in AttributeHandlerRegistry, rather than flowing into code generation. Nullable types are unwrapped to their underlying type before the check.
  • Adds JsonMapperGenerator regression tests verifying that the presence of a complex collection property does not break [UnixTimestamp] conversion (FromUnixTimeSeconds/ToUnixTimeSeconds) or [Ignore] handling on sibling properties.

Testing

  • dotnet test on Goa.Clients.Dynamo.Generator.Tests — 356/356 pass.

🤖 Generated with Claude Code

Im5tu added 2 commits June 8, 2026 21:02
…operties

[UnixTimestamp] applied to an incompatible property type (e.g. a long TTL)
is now filtered out during attribute processing rather than flowing into
code generation. Covers nullable types by unwrapping the underlying type.
…tions

Verify that the presence of a complex collection property does not break
[UnixTimestamp] conversion (FromUnixTimeSeconds/ToUnixTimeSeconds) or [Ignore]
handling on sibling properties.
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces semantic validation to the attribute handler registry, restricting UnixTimestampAttributeInfo to apply only to DateTime and DateTimeOffset properties. A new applicability filter in ProcessAttributes gates attribute insertion, and downstream integration tests verify correct code generation for JSON mappers with complex nested types.

Changes

Attribute Applicability Filtering for UnixTimestamp

Layer / File(s) Summary
Attribute applicability validation
src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs
ProcessAttributes now gates attribute insertion with an applicability predicate via new IsAttributeApplicable helper method. UnixTimestampAttributeInfo is allowed only on DateTime or DateTimeOffset properties (including nullable forms); the helper unwraps nullable types before checking the underlying type.
JSON mapper integration tests
tests/Clients/Goa.Clients.Dynamo.Generator.Tests/CodeGeneration/JsonMapperGeneratorTests.cs
New test suite for JsonMapperGenerator with a TypeHandlerRegistry that includes UnixTimestampTypeHandler and handlers for collections and complex types. Tests verify that Unix-timestamp conversion methods (FromUnixTimeSeconds, ToUnixTimeSeconds) are emitted for applicable DateTimeOffset properties and that properties marked with IgnoreAttributeInfo are excluded from generated code, even when the parent type contains nullable collections of complex nested types.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: filtering the [UnixTimestamp] attribute to only DateTime/DateTimeOffset properties, which matches the core implementation change.
Description check ✅ Passed The description is mostly complete with a clear summary and testing section, though it lacks explicit checkmarks against the template's checklist items for documentation, Native AOT compatibility, and self-review confirmation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dynamo-unixtimestamp-filtering

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs`:
- Line 58: The current check in AttributeHandlerRegistry that returns type.Name
is nameof(DateTime) or nameof(DateTimeOffset) is brittle; update it to use the
symbol's SpecialType for DateTime (e.g., type.SpecialType ==
SpecialType.System_DateTime) and handle DateTimeOffset via a
fully-qualified-symbol check (e.g., compare type.ToDisplayString() or the
INamedTypeSymbol.ContainingNamespace + Name to "System.DateTimeOffset" or use
compilation.GetTypeByMetadataName("System.DateTimeOffset")). Modify the method
that contains the current return (the type-name comparison) to use SpecialType
for System_DateTime and a qualified-name lookup for DateTimeOffset so custom
types named "DateTime" do not match erroneously.
- Around line 54-56: The current nullable unwrap and type checks misclassify
generics and rely on name strings; in AttributeHandlerRegistry (around the
handling of property.Type) only unwrap when the symbol is a Nullable<T> by
checking that the INamedTypeSymbol.OriginalDefinition.SpecialType ==
SpecialType.System_Nullable_T and TypeArguments.Length == 1, then set type =
TypeArguments[0]; replace any name-based checks (type.Name) with robust identity
checks using type.SpecialType (e.g., SpecialType.System_DateTime,
SpecialType.System_DateTimeOffset) or metadata/type symbol equality to detect
DateTime/DateTimeOffset; apply the same stronger check in
UnixTimestampTypeHandler (the class/method that currently uses name-based
comparison) so both places use Nullable detection via
OriginalDefinition.SpecialType and SpecialType-based or metadata identity checks
for date/time types.

In
`@tests/Clients/Goa.Clients.Dynamo.Generator.Tests/Attributes/AttributeHandlerRegistryTests.cs`:
- Around line 235-297: Add tests that verify nullable DateTime/DateTimeOffset
are unwrapped before compatibility checks: create two new tests mirroring
ProcessAttributes_UnixTimestampOnDateTimeOffsetProperty_ShouldBeIncluded but use
MockSymbolFactory.PrimitiveTypes.NullableDateTime and
MockSymbolFactory.PrimitiveTypes.NullableDateTimeOffset for the property types,
register a mock IAttributeHandler that returns a UnixTimestampAttributeInfo,
call AttributeHandlerRegistry.ProcessAttributes on the property symbol, and
assert the UnixTimestampAttributeInfo is preserved (Count == 1 and attributes[0]
is UnixTimestampAttributeInfo); this ensures
AttributeHandlerRegistry.ProcessAttributes correctly handles nullable variants
when checking UnixTimestampAttributeInfo applicability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1191ad4b-1519-4b83-bb56-090df4b6911a

📥 Commits

Reviewing files that changed from the base of the PR and between d3d6de3 and 393df1f.

📒 Files selected for processing (3)
  • src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs
  • tests/Clients/Goa.Clients.Dynamo.Generator.Tests/Attributes/AttributeHandlerRegistryTests.cs
  • tests/Clients/Goa.Clients.Dynamo.Generator.Tests/CodeGeneration/JsonMapperGeneratorTests.cs

Comment on lines +54 to +56
var type = property.Type;
if (type is INamedTypeSymbol { IsGenericType: true } nullable)
type = nullable.TypeArguments[0];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for nullable type handling patterns in the codebase

rg -nP --type=cs -C3 'Nullable.*SpecialType|OriginalDefinition.*Nullable|NullableAnnotation' -g '!**/bin/**' -g '!**/obj/**'

Repository: Im5tu/goa

Length of output: 11271


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs"

# Show the relevant block around the reported lines
nl -ba "$FILE" | sed -n '1,140p' | sed -n '40,90p'

# Also locate the UnixTimestampAttributeInfo block (in case line numbers shifted)
rg -n "UnixTimestampAttributeInfo|hasUnixTimestamp|DateTimeOffset|DateTime" "$FILE"

Repository: Im5tu/goa

Length of output: 96


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs"

# Print with line numbers using awk (nl isn't available)
awk '{print FNR "\t" $0}' "$FILE" | sed -n '40,90p'

# Locate UnixTimestamp-related logic
rg -n "UnixTimestampAttributeInfo|hasUnixTimestamp|DateTimeOffset|DateTime" "$FILE"

Repository: Im5tu/goa

Length of output: 2050


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "OriginalDefinition\.SpecialType\s*==\s*SpecialType\.System_Nullable_T|System_Nullable_T" src/Clients/Goa.Clients.Dynamo.Generator -S

FILE="src/Clients/Goa.Clients.Dynamo.Generator/Models/PropertyInfo.cs"
awk '{print FNR "\t" $0}' "$FILE" | sed -n '1,120p'

FILE2="src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs"
awk '{print FNR "\t" $0}' "$FILE2" | sed -n '1,140p'

Repository: Im5tu/goa

Length of output: 6903


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find UnixTimestamp attribute info + attribute definition
rg -n "UnixTimestampAttributeInfo|UnixTimestampAttribute|UnixTimestamp" src/Clients/Goa.Clients.Dynamo.Generator -S

# Check for tests referencing UnixTimestamp applicability
rg -n "UnixTimestamp" tests/Clients/Goa.Clients.Dynamo.Generator.Tests -S || true

# Inspect AttributeHandlerRegistry usage around UnixTimestamp (if any)
rg -n "IsAttributeApplicable\\(|AttributeHandlerRegistry" src/Clients/Goa.Clients.Dynamo.Generator -S

Repository: Im5tu/goa

Length of output: 38291


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect UnixTimestampTypeHandler.CanHandle logic
FILE="src/Clients/Goa.Clients.Dynamo.Generator/TypeHandlers/UnixTimestampTypeHandler.cs"
awk '{print FNR "\t" $0}' "$FILE" | sed -n '1,220p'

# Inspect AttributeHandlerRegistry tests for UnixTimestamp filtering cases
TESTFILE="tests/Clients/Goa.Clients.Dynamo.Generator.Tests/Attributes/AttributeHandlerRegistryTests.cs"
awk '{print FNR "\t" $0}' "$TESTFILE" | sed -n '200,340p'

# Inspect mock primitive types (DateTime/DateTimeOffset) if it uses name-based matching
MOCKFILE="tests/Clients/Goa.Clients.Dynamo.Generator.Tests/Helpers/MockSymbolFactory.cs"
awk '{print FNR "\t" $0}' "$MOCKFILE" | sed -n '1,130p'

Repository: Im5tu/goa

Length of output: 18990


Fix UnixTimestamp attribute type validation (only unwrap Nullable and use stronger type identity)

  • src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs:55-56 unwraps any generic INamedTypeSymbol via TypeArguments[0], so List<DateTime>-like cases can be misclassified; unwrap only when OriginalDefinition.SpecialType == SpecialType.System_Nullable_T (and TypeArguments.Length == 1, like PropertyInfo.UnderlyingType).
  • src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs:58 uses name-based type.Name matching; switch to type.SpecialType (e.g., System_DateTime / System_DateTimeOffset) or metadata identity to prevent unrelated types named DateTime/DateTimeOffset.
  • Also update src/Clients/Goa.Clients.Dynamo.Generator/TypeHandlers/UnixTimestampTypeHandler.cs:18, which repeats the same name-based check, otherwise the overall validation remains bypassable.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs`
around lines 54 - 56, The current nullable unwrap and type checks misclassify
generics and rely on name strings; in AttributeHandlerRegistry (around the
handling of property.Type) only unwrap when the symbol is a Nullable<T> by
checking that the INamedTypeSymbol.OriginalDefinition.SpecialType ==
SpecialType.System_Nullable_T and TypeArguments.Length == 1, then set type =
TypeArguments[0]; replace any name-based checks (type.Name) with robust identity
checks using type.SpecialType (e.g., SpecialType.System_DateTime,
SpecialType.System_DateTimeOffset) or metadata/type symbol equality to detect
DateTime/DateTimeOffset; apply the same stronger check in
UnixTimestampTypeHandler (the class/method that currently uses name-based
comparison) so both places use Nullable detection via
OriginalDefinition.SpecialType and SpecialType-based or metadata identity checks
for date/time types.

Comment thread src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs (1)

80-81: 💤 Low value

Consider using ToDisplayString() on the type symbol directly.

The current implementation correctly checks both name and namespace, addressing the past review concern. However, the past review suggested using type.ToDisplayString() == "System.DateTimeOffset", which is slightly more concise and eliminates the theoretical edge case where a user defines namespace System { struct DateTimeOffset {} }.

Both approaches work correctly in practice. The suggested alternative is marginally cleaner:

return type.ToDisplayString() == "System.DateTimeOffset";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs`
around lines 80 - 81, Replace the separate type name and namespace checks with a
single direct call to ToDisplayString() on the type symbol. In the return
statement that validates the DateTimeOffset type, change the condition from
checking type.Name == nameof(DateTimeOffset) &&
type.ContainingNamespace?.ToDisplayString() == "System" to simply
type.ToDisplayString() == "System.DateTimeOffset". This is more concise and
eliminates the edge case where a user could define a custom DateTimeOffset in
the System namespace.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs`:
- Around line 70-82: The UnixTimestampTypeHandler class uses brittle name-only
comparisons at line 18 to check for DateTime and DateTimeOffset types. Replace
the current comparison logic (underlyingType.Name == nameof(DateTime) ||
underlyingType.Name == nameof(DateTimeOffset)) with the same robust symbol-based
approach used in the IsDateTimeType method: check if the type's SpecialType is
System_DateTime, and for DateTimeOffset, verify both the type name and the
fully-qualified namespace using ToDisplayString() to ensure proper type
identification.

---

Nitpick comments:
In
`@src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs`:
- Around line 80-81: Replace the separate type name and namespace checks with a
single direct call to ToDisplayString() on the type symbol. In the return
statement that validates the DateTimeOffset type, change the condition from
checking type.Name == nameof(DateTimeOffset) &&
type.ContainingNamespace?.ToDisplayString() == "System" to simply
type.ToDisplayString() == "System.DateTimeOffset". This is more concise and
eliminates the edge case where a user could define a custom DateTimeOffset in
the System namespace.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0c159f18-0af9-4f65-90b2-351881329aea

📥 Commits

Reviewing files that changed from the base of the PR and between 393df1f and e2b5c8f.

📒 Files selected for processing (2)
  • src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs
  • tests/Clients/Goa.Clients.Dynamo.Generator.Tests/Attributes/AttributeHandlerRegistryTests.cs

Comment on lines +70 to +82
/// <summary>
/// Determines whether the given type is System.DateTime or System.DateTimeOffset
/// using robust symbol identity rather than brittle name comparisons.
/// </summary>
private static bool IsDateTimeType(ITypeSymbol type)
{
if (type.SpecialType == SpecialType.System_DateTime)
return true;

// DateTimeOffset has no SpecialType, so identify it by its fully-qualified name.
return type.Name == nameof(DateTimeOffset)
&& type.ContainingNamespace?.ToDisplayString() == "System";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify UnixTimestampTypeHandler uses consistent type checking

# Search for the CanHandle method or type-checking logic in UnixTimestampTypeHandler
rg -n -A10 "class UnixTimestampTypeHandler|CanHandle|IsDateTimeType" src/Clients/Goa.Clients.Dynamo.Generator/TypeHandlers/UnixTimestampTypeHandler.cs

Repository: Im5tu/goa

Length of output: 692


Update UnixTimestampTypeHandler to use robust symbol-based type checking.

Line 18 currently uses brittle name-only comparisons (underlyingType.Name == nameof(DateTime) || underlyingType.Name == nameof(DateTimeOffset)). Update it to match the robust type identification in AttributeHandlerRegistry.IsDateTimeType(): use SpecialType.System_DateTime for DateTime and namespace-qualified name checking for DateTimeOffset.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/Clients/Goa.Clients.Dynamo.Generator/Attributes/AttributeHandlerRegistry.cs`
around lines 70 - 82, The UnixTimestampTypeHandler class uses brittle name-only
comparisons at line 18 to check for DateTime and DateTimeOffset types. Replace
the current comparison logic (underlyingType.Name == nameof(DateTime) ||
underlyingType.Name == nameof(DateTimeOffset)) with the same robust symbol-based
approach used in the IsDateTimeType method: check if the type's SpecialType is
System_DateTime, and for DateTimeOffset, verify both the type name and the
fully-qualified namespace using ToDisplayString() to ensure proper type
identification.

@Im5tu Im5tu merged commit ce8c084 into main Jun 18, 2026
2 of 3 checks passed
@Im5tu Im5tu deleted the fix/dynamo-unixtimestamp-filtering branch June 18, 2026 11:59
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.

1 participant