Skip to content

fix(binder): normalize db tags#55

Merged
cnlangzi merged 1 commit into
mainfrom
fix/bind
Dec 1, 2025
Merged

fix(binder): normalize db tags#55
cnlangzi merged 1 commit into
mainfrom
fix/bind

Conversation

@cnlangzi

@cnlangzi cnlangzi commented Dec 1, 2025

Copy link
Copy Markdown
Member

Summary by Sourcery

Normalize struct binder db tag handling and add coverage for underscore and case-insensitive column mappings.

Bug Fixes:

  • Ensure struct fields with db tags containing underscores are correctly mapped by normalizing tags to match column name processing.

Tests:

  • Add binder tests covering structs with underscore db tags, structs without tags, various column name casings, and slice binding behavior.

Add MigrationStatus (New|Executed|Modified). Optimize checksum-first query; avoid duplicate records for renamed scripts. Normalize  tags and add tests. Fix DTC test.
@sourcery-ai

sourcery-ai Bot commented Dec 1, 2025

Copy link
Copy Markdown

Reviewer's Guide

Normalizes struct db tag keys in the binder to match the existing column-name normalization (lowercased, underscores removed) and adds tests covering binding behavior with tagged/untagged structs, varying column name cases, and slice binding against a SQLite-backed users table.

Sequence diagram for binding with normalized db tags

sequenceDiagram
    actor Test as TestCode
    participant DB as SQLiteDB
    participant Rows as SQLRows
    participant BinderFactory as binder_struct_go
    participant SB as structBinder
    participant User as UserStruct

    Test->>DB: Execute query SELECT * FROM users
    DB-->>Test: Rows handle
    Test->>BinderFactory: newStructBinder(UserType, UserValue)
    BinderFactory-->>SB: structBinder instance

    loop For each column in rows metadata
        SB->>SB: read db tag or field name
        SB->>SB: normalizedTag = toLower(removeUnderscores(tagName))
        SB->>SB: fieldIndexes[normalizedTag] = fieldIndex
        SB->>SB: append fieldColumnNames with original tagName
    end

    loop For each row in Rows
        Test->>Rows: Scan next row
        Rows-->>Test: columnValues, columnNames
        Test->>SB: bindRow(columnValues, columnNames)
        SB->>SB: normalize each columnName (lowercase, remove underscores)
        SB->>SB: lookup fieldIndex = fieldIndexes[normalizedColumnName]
        SB->>User: set struct field using fieldIndex and value
    end

    SB-->>Test: bound User instances
Loading

Class diagram for updated struct binder tag normalization

classDiagram
    class Binder {
        <<interface>>
    }

    class structBinder {
        map~string,int~ fieldIndexes
        string[] fieldColumnNames
        reflectType type
        reflectValue value
        newRowBinder() RowBinder
        bindRow(scanner Scanner) error
    }

    class RowBinder {
        <<interface>>
    }

    class Scanner {
        <<interface>>
    }

    Binder <|.. structBinder

    class binder_struct_go {
        +newStructBinder(t reflectType, v reflectValue) Binder
        -normalizeTagName(tagName string) string
    }

    binder_struct_go ..> structBinder : creates
    binder_struct_go ..> Binder

    note for structBinder "fieldIndexes now uses normalized db tag keys (lowercased, underscores removed) while fieldColumnNames preserves original tag names"

    %% Representation of the updated logic inside newStructBinder
    structBinder o-- map_string_int_fieldIndexes : uses
    structBinder o-- string_array_fieldColumnNames : uses

    class map_string_int_fieldIndexes {
        +set(key string, index int)
        +get(key string) int
    }

    class string_array_fieldColumnNames {
        +append(name string)
        +get(i int) string
    }
Loading

File-Level Changes

Change Details Files
Normalize struct db tags in the struct binder to align with column name normalization logic.
  • When a struct field has a non-empty db tag, compute a normalized key by lowercasing the tag and removing underscores.
  • Use the normalized tag string as the key in sb.fieldIndexes instead of the raw tag value while preserving the original tag in sb.fieldColumnNames.
binder_struct.go
Add integration-style tests for struct binding behavior with db tags (including underscores), no tags, and different DB column name casings.
  • Introduce UserWithUnderscoreTag and UserWithoutTag structs to exercise binding with and without db tags.
  • Set up an in-memory SQLite database with a users table and seed data for binding tests.
  • Add subtests verifying binding works with underscored tags, no tags, uppercase and mixed-case column names, and slice binding over multiple rows using rows.Bind.
binder_test.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepsource-io

deepsource-io Bot commented Dec 1, 2025

Copy link
Copy Markdown

Here's the code health analysis summary for commits d222046..37c7059. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource Go LogoGo✅ SuccessView Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • The tag normalization logic (strings.ToLower(strings.ReplaceAll(tagName, "_", ""))) should ideally be shared with whatever normalization is used for column names to avoid drift if one side changes in the future.
  • If db tags can include options (e.g., db:"first_name,omitempty"), the current normalization will treat the whole tag string as the name; consider splitting on , before normalizing to avoid unexpected behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The tag normalization logic (`strings.ToLower(strings.ReplaceAll(tagName, "_", ""))`) should ideally be shared with whatever normalization is used for column names to avoid drift if one side changes in the future.
- If `db` tags can include options (e.g., `db:"first_name,omitempty"`), the current normalization will treat the whole tag string as the name; consider splitting on `,` before normalizing to avoid unexpected behavior.

## Individual Comments

### Comment 1
<location> `binder_struct.go:29-30` </location>
<code_context>
 		if tagName != "" {
-			sb.fieldIndexes[tagName] = i
+			// Normalize tag name to match column name processing: remove underscores and lowercase
+			normalizedTag := strings.ToLower(strings.ReplaceAll(tagName, "_", ""))
+			sb.fieldIndexes[normalizedTag] = i
 			sb.fieldColumnNames = append(sb.fieldColumnNames, tagName)
 			continue
</code_context>

<issue_to_address>
**issue (bug_risk):** Normalized tag keys may collide, silently overwriting earlier fields.

Because normalization removes underscores and lowercases, tags like `user_id` and `UserId` will both map to the same `normalizedTag`, so the later field silently overwrites the earlier one in `sb.fieldIndexes`. If that’s not intended, consider detecting collisions and either failing, logging, or skipping the overwrite so the behavior is explicit instead of silent.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread binder_struct.go
@codecov

codecov Bot commented Dec 1, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.75%. Comparing base (d222046) to head (37c7059).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #55      +/-   ##
==========================================
+ Coverage   77.58%   77.75%   +0.16%     
==========================================
  Files          46       46              
  Lines        1896     1897       +1     
==========================================
+ Hits         1471     1475       +4     
+ Misses        304      300       -4     
- Partials      121      122       +1     
Flag Coverage Δ
Unit-Tests 77.75% <100.00%> (+0.16%) ⬆️

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.

@cnlangzi
cnlangzi enabled auto-merge December 1, 2025 08:10
@cnlangzi
cnlangzi disabled auto-merge December 1, 2025 08:10
@cnlangzi
cnlangzi merged commit 8a1c74b into main Dec 1, 2025
6 checks passed
@cnlangzi
cnlangzi deleted the fix/bind branch December 1, 2025 08:11
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