Skip to content

[refactor] SearchRanked duplicates scanNode's 16-column scan #232

Description

@radimsem

Summary

SearchRanked in pkg/store/search.go open-codes the same 16-field rows.Scan as scanNode in pkg/store/node.go, just to capture a trailing rank column. Adding or removing a nodes column now requires editing two scan sites in lock-step.

Location

  • pkg/store/search.go:34-48 — the inline scan
  • pkg/store/node.go:76-92scanNode
  • pkg/store/queries.gonodeColumns constant

Category

refactor

Impact

Medium. Three-way drift risk (the nodeColumns constant, scanNode, SearchRanked's inline scan) on every schema change. Easy to update two of three and ship a silent bug.

Rationale

// pkg/store/node.go:76-92
func scanNode(r RowScanner) (*Node, error) {
    var n Node
    var parentID sql.NullString
    err := r.Scan(
        &n.ID, &parentID, &n.SourceFile, &n.NodeType, &n.Depth,
        &n.Label, &n.Content, &n.Format, &n.TokenCount, &n.ContentHash,
        &n.Temperature, &n.AccessCount, &n.LastAccessed,
        &n.CreatedAt, &n.UpdatedAt, &n.Pinned,
    )
    ...
}
// pkg/store/search.go:36-48
var n Node
var parentID sql.NullString
var rank float64

err := rows.Scan(
    &n.ID, &parentID, &n.SourceFile, &n.NodeType, &n.Depth,
    &n.Label, &n.Content, &n.Format, &n.TokenCount, &n.ContentHash,
    &n.Temperature, &n.AccessCount, &n.LastAccessed,
    &n.CreatedAt, &n.UpdatedAt, &n.Pinned, &rank,
)

The 16 node fields are identical; only &rank is appended.

Suggested change direction

Add a small helper in pkg/store/node.go that scans the 16 node fields plus one trailing pointer arg:

func scanNodeWithExtra(r RowScanner, extra ...any) (*Node, error) {
    var n Node
    var parentID sql.NullString
    args := append([]any{
        &n.ID, &parentID, &n.SourceFile, &n.NodeType, &n.Depth,
        &n.Label, &n.Content, &n.Format, &n.TokenCount, &n.ContentHash,
        &n.Temperature, &n.AccessCount, &n.LastAccessed,
        &n.CreatedAt, &n.UpdatedAt, &n.Pinned,
    }, extra...)
    if err := r.Scan(args...); err != nil {
        return nil, err
    }
    n.ParentID = parentID.String
    return &n, nil
}

SearchRanked becomes:

var rank float64
n, err := scanNodeWithExtra(rows, &rank)

Keep the existing scanNode as the zero-extra convenience wrapper. One scan list, one place to update on schema changes. No new abstraction beyond what's already implicit in RowScanner.

Filed by the nightly enhancement-scanner routine at commit f11c9f1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    auto-reviewFiled by the nightly enhancement-scanner routinerefactorCode refactoring / architecture cleanup

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions