Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions example/pkg/database/generated_wrapper_mysql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions generator/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,24 @@ func FixAcronyms(content []byte) []byte {
// 3. Mid: `([a-z])(Acronym)([A-Z])` - acronym in middle of camelCase, e.g., Id in userIdMore.
// 4. End: `([a-z])(Acronym)$` - acronym at end of identifier, e.g., Id in userId.
// 5. NonLetter: `([a-z])(Acronym)([^A-Za-z])` - acronym followed by non-letter.
// For Id, we exclude '(' to avoid transforming method calls like LastInsertId().
regexStart := regexp.MustCompile(`^(` + a.pattern + `)([A-Z])`)
regexAfterUpper := regexp.MustCompile(`([A-Z])(` + a.pattern + `)([A-Z])`)
regexMid := regexp.MustCompile(`([a-z])(` + a.pattern + `)([A-Z])`)
regexEnd := regexp.MustCompile(`([a-z])(` + a.pattern + `)$`)
regexNonLetter := regexp.MustCompile(`([a-z])(` + a.pattern + `)([^A-Za-z])`)

// For Id, exclude '(' to preserve method calls like res.LastInsertId()
// For Url, exclude ':' and ',' to preserve struct field names like NewUrl, OldUrl
nonLetterClass := `[^A-Za-z]`

switch a.pattern {
case "Id":
nonLetterClass = `[^A-Za-z(]`
case "Url":
nonLetterClass = `[^A-Za-z:,]`
}

regexNonLetter := regexp.MustCompile(`([a-z])(` + a.pattern + `)(` + nonLetterClass + `)`)
Comment on lines +101 to +112
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

While this logic correctly fixes the issue, compiling regular expressions inside this for loop is inefficient. The compilation happens on every call to FixAcronyms for every acronym, which can be a performance bottleneck.

To improve this, consider pre-compiling all the regular expressions once at package initialization using an init() function. You could store them in a global variable (e.g., a slice of structs, where each struct holds the compiled regexes for an acronym). This ensures the expensive compilation step is performed only once when the package is loaded.


// Start case: replace with replacement followed by ${2} (the uppercase after).
result = regexStart.ReplaceAllString(result, a.replacement+"${2}")
Expand Down Expand Up @@ -124,7 +137,7 @@ func writeFile(dir, filename string, content []byte) {
// 2. Format with gofumpt
formatted, err := format.Source(withImports, format.Options{
LangVersion: "",
ExtraRules: true,
ExtraRules: false,
})
if err != nil {
log.Println(string(withImports))
Expand Down
30 changes: 30 additions & 0 deletions generator/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,36 @@ func TestFixAcronyms(t *testing.T) {
input: "",
expected: "",
},
{
name: "LastInsertId in method call should not be transformed",
input: "res.LastInsertId()",
expected: "res.LastInsertId()",
},
{
name: "SetId in method call should not be transformed",
input: "obj.SetId(123)",
expected: "obj.SetId(123)",
},
{
name: "userId in variable assignment should become userID",
input: "userId = 123",
expected: "userID = 123",
},
{
name: "NewUrl in struct literal should remain NewUrl",
input: "NewUrl: \"value\"",
expected: "NewUrl: \"value\"",
},
{
name: "OldUrl in struct literal should remain OldUrl",
input: "OldUrl: \"value\"",
expected: "OldUrl: \"value\"",
},
{
name: "profileUrl in assignment should become profileURL",
input: "profileUrl = \"https://example.com\"",
expected: "profileURL = \"https://example.com\"",
},
}

for _, tt := range tests {
Expand Down
Loading