Skip to content
Merged
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
10 changes: 8 additions & 2 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ package sqlorm

import (
"reflect"
"regexp"
"strings"

"github.com/tinh-tinh/tinhtinh/v2/dto/validator"
"gorm.io/gorm"
)

// validColumnRegex matches valid SQL column names:
// - Must start with a letter or underscore
// - Can contain letters, numbers, and underscores
// - Optionally allows table.column format
var validColumnRegex = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)?$`)

type Query interface {
func(qb *QueryBuilder) | interface{}
}
Expand Down Expand Up @@ -164,5 +170,5 @@ func (q *QueryBuilder) Raw(sql string, values ...interface{}) *QueryBuilder {
}

func isValidColumn(column string) bool {
return validator.IsAlphanumeric(column)
return validColumnRegex.MatchString(column)
}
48 changes: 47 additions & 1 deletion builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,16 @@ func Test_IsValidColumn(t *testing.T) {
"col+name",
"col name",
"col-name",
"col.name",
// "col.name" is now valid - represents table.column format
"col:name",
"col;name",
"col'name",
"col\"name",
"col{name}",
"1column", // starts with number
".column", // starts with dot
"table.", // ends with dot
"table..column", // double dot
}

// Test Equal with invalid columns
Expand Down Expand Up @@ -406,4 +410,46 @@ func Test_IsValidColumn(t *testing.T) {
require.Nil(t, err)
require.Equal(t, 1, len(docs))
})

// Test snake_case column names are valid
t.Run("ValidColumn_SnakeCase", func(t *testing.T) {
// These should be accepted as valid column names
validSnakeCases := []string{
"employee_id",
"created_at",
"updated_at",
"deleted_at",
"first_name",
"last_name",
"user_profile_id",
"_private",
"Name",
"value123",
}
for _, col := range validSnakeCases {
// Just verify these don't cause issues - they should pass validation
_, err := repo.FindAll(func(qb *sqlorm.QueryBuilder) {
qb.Equal(col, "test")
})
// The query might fail due to column not existing, but validation should pass
// We're just testing that isValidColumn accepts snake_case
_ = err
}
})

// Test qualified table.column format is valid
t.Run("ValidColumn_QualifiedName", func(t *testing.T) {
validQualified := []string{
"table.column",
"users.id",
"employees.first_name",
"_private.field",
}
for _, col := range validQualified {
_, err := repo.FindAll(func(qb *sqlorm.QueryBuilder) {
qb.Equal(col, "test")
})
_ = err
}
})
}