Skip to content

Commit b6b7f5e

Browse files
Merge pull request #74 from oracle-samples/joboon-CaseInsensitiveFieldMatching
support case insensitive field matching
2 parents 45d606f + 70a7377 commit b6b7f5e

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

oracle/oracle.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ func (d Dialector) Initialize(db *gorm.DB) (err error) {
109109
callback.Update().Replace("gorm:update", Update)
110110
callback.Query().Before("gorm:query").Register("oracle:before_query", BeforeQuery)
111111

112+
if d.SkipQuoteIdentifiers {
113+
// When identifiers are not quoted, columns are returned by Oracle in uppercase.
114+
// Fields in the models may be lower case for compatibility with other databases.
115+
// Match them up with the fields using the column mapping.
116+
oracleCaseHandler := "oracle:case_handler"
117+
if callback.Query().Get(oracleCaseHandler) == nil {
118+
if err := callback.Query().Before("gorm:query").Register(oracleCaseHandler, MismatchedCaseHandler); err != nil {
119+
return err
120+
}
121+
}
122+
}
123+
112124
maps.Copy(db.ClauseBuilders, OracleClauseBuilders())
113125

114126
if d.Conn == nil {

oracle/query.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,19 @@ func BeforeQuery(db *gorm.DB) {
6565
}
6666
}
6767
}
68+
69+
// MismatchedCaseHandler handles Oracle Case Insensitivity.
70+
// When identifiers are not quoted, columns are returned by Oracle in uppercase.
71+
// Fields in the models may be lower case for compatibility with other databases.
72+
// Match them up with the fields using the column mapping.
73+
func MismatchedCaseHandler(gormDB *gorm.DB) {
74+
if gormDB.Statement == nil || gormDB.Statement.Schema == nil {
75+
return
76+
}
77+
if len(gormDB.Statement.Schema.Fields) > 0 && gormDB.Statement.ColumnMapping == nil {
78+
gormDB.Statement.ColumnMapping = map[string]string{}
79+
}
80+
for _, field := range gormDB.Statement.Schema.Fields {
81+
gormDB.Statement.ColumnMapping[strings.ToUpper(field.DBName)] = field.Name
82+
}
83+
}

tests/config_test.go

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,57 @@ func TestSkipQuoteIdentifiers(t *testing.T) {
7878
t.Errorf("Failed to get column: name")
7979
}
8080

81+
student := Student{ID: 1, Name: "John"}
82+
if err := db.Model(&Student{}).Create(&student).Error; err != nil {
83+
t.Errorf("Failed to insert student, got %v", err)
84+
}
85+
86+
var result Student
87+
if err := db.First(&result).Error; err != nil {
88+
t.Errorf("Failed to query first student, got %v", err)
89+
}
90+
91+
if result.ID != student.ID {
92+
t.Errorf("id should be %v, but got %v", student.ID, result.ID)
93+
}
94+
95+
if result.Name != student.Name {
96+
t.Errorf("name should be %v, but got %v", student.Name, result.Name)
97+
}
98+
}
99+
100+
func TestSkipQuoteIdentifiersSQL(t *testing.T) {
101+
db, err := openTestDBWithOptions(
102+
&oracle.Config{SkipQuoteIdentifiers: true},
103+
&gorm.Config{Logger: newLogger})
104+
if err != nil {
105+
t.Fatalf("failed to connect database, got error %v", err)
106+
}
81107
dryrunDB := db.Session(&gorm.Session{DryRun: true})
82108

83-
result := dryrunDB.Model(&Student{}).Create(&Student{ID: 1, Name: "John"})
109+
insertedStudent := Student{ID: 1, Name: "John"}
110+
result := dryrunDB.Model(&Student{}).Create(&insertedStudent)
111+
84112
if !regexp.MustCompile(`^INSERT INTO STUDENTS \(name,id\) VALUES \(:1,:2\)$`).MatchString(result.Statement.SQL.String()) {
85113
t.Errorf("invalid insert SQL, got %v", result.Statement.SQL.String())
86114
}
87115

88-
result = dryrunDB.First(&Student{})
116+
// Test First
117+
var firstStudent Student
118+
result = dryrunDB.First(&firstStudent)
119+
89120
if !regexp.MustCompile(`^SELECT \* FROM STUDENTS ORDER BY STUDENTS\.id FETCH NEXT 1 ROW ONLY$`).MatchString(result.Statement.SQL.String()) {
90121
t.Fatalf("SQL should include selected names, but got %v", result.Statement.SQL.String())
91122
}
92123

93-
result = dryrunDB.Find(&Student{ID: 1, Name: "John"})
94-
if !regexp.MustCompile(`^SELECT \* FROM STUDENTS WHERE STUDENTS\.id = :1$`).MatchString(result.Statement.SQL.String()) {
124+
// Test Find
125+
var foundStudent Student
126+
result = dryrunDB.Find(foundStudent, "id = ?", insertedStudent.ID)
127+
if !regexp.MustCompile(`^SELECT \* FROM STUDENTS WHERE id = :1$`).MatchString(result.Statement.SQL.String()) {
95128
t.Fatalf("SQL should include selected names, but got %v", result.Statement.SQL.String())
96129
}
97130

131+
// Test Save
98132
result = dryrunDB.Save(&Student{ID: 2, Name: "Mary"})
99133
if !regexp.MustCompile(`^UPDATE STUDENTS SET name=:1 WHERE id = :2$`).MatchString(result.Statement.SQL.String()) {
100134
t.Fatalf("SQL should include selected names, but got %v", result.Statement.SQL.String())

0 commit comments

Comments
 (0)