Skip to content

perf: reuse NamingStrategy and fix fragile param counting in SQL template renderer #59

Description

@pageton

Summary

Two per-field inefficiencies in the code generation hot path:

1. schema.NamingStrategy created per field

utils.go:153-162generateDBName is called for every exported field of every struct:

func generateDBName(fieldName, gormTag string) string {
    // ...
    ns := schema.NamingStrategy{IdentifierMaxLength: 64}
    return ns.ColumnName("", fieldName)
}

NamingStrategy is stateless — a single package-level instance suffices:

var namingStrategy = schema.NamingStrategy{IdentifierMaxLength: 64}

2. Param counting in RenderSQLTemplate is fragile

sqlparser.go:329-343 — After building the AST, the renderer estimates param count by:

  1. Splitting emitted Go code into lines
  2. Counting commas in _params = append(_params, ...) lines
  3. Detecting for loops and multiplying by 4
for _, line := range strings.Split(code, "\n") {
    if strings.Index(code, "\tfor ") > 0 {
        baseCount = 4
    }
    if strings.Contains(line, "_params = append(_params") {
        count += strings.Count(line, ",") * baseCount
    }
}

Problems:

  • Commas inside string literals (e.g. CONCAT("a, b")) cause overcounting
  • The for detection (strings.Index(code, "\tfor ") > 0) checks the entire code block, not the current line — once one for is found, all subsequent params are multiplied by 4
  • The 4× multiplier is a hardcoded guess

Fix: Track param count during AST construction. Each TextNode.Emit already knows how many params it appends — return that count alongside the code string. ForNode and IfNode can sum their children's counts.

Expected Impact

Minor per-field improvement × thousands of fields = meaningful reduction in generation time. The param counting fix also prevents incorrect _params slice preallocation (which currently causes either overallocation or underallocation depending on the code).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions