diff --git a/query.go b/query.go index f41ea38..e87a010 100644 --- a/query.go +++ b/query.go @@ -10,6 +10,19 @@ import ( const tagName = "gormlike" +func likeCastType(dialect string) string { + switch strings.ToLower(dialect) { + case "mysql", "mariadb": + return "CHAR" + default: + return "VARCHAR" + } +} + +func likeCondition(dialect, column string) string { + return fmt.Sprintf("CAST(%s as %s) LIKE ?", column, likeCastType(dialect)) +} + //nolint:gocognit,cyclop // is a complex, recursive function func (d *gormLike) replaceExpressions(db *gorm.DB, expressions []clause.Expression) []clause.Expression { for index, cond := range expressions { @@ -55,7 +68,7 @@ func (d *gormLike) replaceExpressions(db *gorm.DB, expressions []clause.Expressi continue } - condition := fmt.Sprintf("CAST(%s as varchar) LIKE ?", column.Name) + condition := likeCondition(db.Dialector.Name(), column.Name) if d.replaceCharacter != "" { value = strings.ReplaceAll(value, d.replaceCharacter, "%") @@ -99,7 +112,7 @@ func (d *gormLike) replaceExpressions(db *gorm.DB, expressions []clause.Expressi // If there are no % AND there aren't only replaceable characters, just skip it because it's a normal query if strings.Contains(value, "%") || (d.replaceCharacter != "" && strings.Contains(value, d.replaceCharacter)) { - condition = fmt.Sprintf("CAST(%s as varchar) LIKE ?", column.Name) + condition = likeCondition(db.Dialector.Name(), column.Name) if d.replaceCharacter != "" { value = strings.ReplaceAll(value, d.replaceCharacter, "%") diff --git a/query_test.go b/query_test.go index f7aae61..6c4b558 100644 --- a/query_test.go +++ b/query_test.go @@ -10,6 +10,51 @@ import ( "gorm.io/gorm" ) +func TestLikeCastType(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + dialect string + expected string + }{ + "mysql uses char": { + dialect: "mysql", + expected: "CHAR", + }, + "mariadb uses char": { + dialect: "mariadb", + expected: "CHAR", + }, + "case-insensitive mysql": { + dialect: "MySQL", + expected: "CHAR", + }, + "postgres defaults to varchar": { + dialect: "postgres", + expected: "VARCHAR", + }, + "sqlite defaults to varchar": { + dialect: "sqlite", + expected: "VARCHAR", + }, + } + + for name, testData := range tests { + t.Run(name, func(t *testing.T) { + t.Parallel() + + assert.Equal(t, testData.expected, likeCastType(testData.dialect)) + }) + } +} + +func TestLikeCondition(t *testing.T) { + t.Parallel() + + assert.Equal(t, "CAST(type as CHAR) LIKE ?", likeCondition("mysql", "type")) + assert.Equal(t, "CAST(type as VARCHAR) LIKE ?", likeCondition("postgres", "type")) +} + //nolint:maintidx // Acceptable func TestGormLike_Initialize_TriggersLikingCorrectly(t *testing.T) { t.Parallel()