Skip to content

Commit 6272731

Browse files
committed
exclues autoincremented fields from the update sql, and fix SkipQuoteIdentifiers
1 parent 12346fa commit 6272731

File tree

5 files changed

+161
-38
lines changed

5 files changed

+161
-38
lines changed

oracle/clause_builder.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,8 @@ func shouldIncludeColumn(stmt *gorm.Statement, columnName string) bool {
503503
stmt.Schema.PrioritizedPrimaryField.AutoIncrement &&
504504
stmt.Schema.PrioritizedPrimaryField.DBName == columnName {
505505
return false
506+
} else if stmt.Schema.LookUpField(columnName).AutoIncrement {
507+
return false
506508
}
507509
return true
508510
}

oracle/create.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ func buildBulkMergePLSQL(db *gorm.DB, createValues clause.Values, onConflictClau
398398
schema.PrioritizedPrimaryField.AutoIncrement &&
399399
strings.EqualFold(schema.PrioritizedPrimaryField.DBName, column.Name) {
400400
isAutoIncrement = true
401+
} else if stmt.Schema.LookUpField(column.Name).AutoIncrement {
402+
isAutoIncrement = true
401403
}
402404

403405
if !isConflictColumn && !isAutoIncrement {
@@ -520,7 +522,7 @@ func buildBulkMergePLSQL(db *gorm.DB, createValues clause.Values, onConflictClau
520522
" IF l_affected_records.COUNT > %d THEN :%d := l_affected_records(%d).",
521523
rowIdx, outParamIndex+1, rowIdx+1,
522524
))
523-
writeQuotedIdentifier(&plsqlBuilder, column)
525+
db.QuoteTo(&plsqlBuilder, column)
524526
plsqlBuilder.WriteString("; END IF;\n")
525527
} else {
526528
// datatypes.JSON (text-based) -> serialize to CLOB
@@ -529,13 +531,13 @@ func buildBulkMergePLSQL(db *gorm.DB, createValues clause.Values, onConflictClau
529531
" IF l_affected_records.COUNT > %d THEN :%d := JSON_SERIALIZE(l_affected_records(%d).",
530532
rowIdx, outParamIndex+1, rowIdx+1,
531533
))
532-
writeQuotedIdentifier(&plsqlBuilder, column)
534+
db.QuoteTo(&plsqlBuilder, column)
533535
plsqlBuilder.WriteString(" RETURNING CLOB); END IF;\n")
534536
}
535537
} else {
536538
stmt.Vars = append(stmt.Vars, sql.Out{Dest: createTypedDestination(field)})
537539
plsqlBuilder.WriteString(fmt.Sprintf(" IF l_affected_records.COUNT > %d THEN :%d := l_affected_records(%d).", rowIdx, outParamIndex+1, rowIdx+1))
538-
writeQuotedIdentifier(&plsqlBuilder, column)
540+
db.QuoteTo(&plsqlBuilder, column)
539541
plsqlBuilder.WriteString("; END IF;\n")
540542
}
541543
outParamIndex++
@@ -696,6 +698,8 @@ func shouldIncludeColumnInInsert(stmt *gorm.Statement, columnName string) bool {
696698
stmt.Schema.PrioritizedPrimaryField.AutoIncrement &&
697699
strings.EqualFold(stmt.Schema.PrioritizedPrimaryField.DBName, columnName) {
698700
return false
701+
} else if stmt.Schema.LookUpField(columnName).AutoIncrement {
702+
return false
699703
}
700704
return true
701705
}

oracle/delete.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,14 @@ func buildBulkDeletePLSQL(db *gorm.DB) {
299299
" IF l_deleted_records.COUNT > %d THEN :%d := l_deleted_records(%d).",
300300
rowIdx, outParamIndex+1, rowIdx+1,
301301
))
302-
writeQuotedIdentifier(&plsqlBuilder, column)
302+
db.QuoteTo(&plsqlBuilder, column)
303303
plsqlBuilder.WriteString("; END IF;\n")
304304
} else {
305305
// JSON -> text bind
306306
stmt.Vars = append(stmt.Vars, sql.Out{Dest: new(string)})
307307
plsqlBuilder.WriteString(fmt.Sprintf(" IF l_deleted_records.COUNT > %d THEN\n", rowIdx))
308308
plsqlBuilder.WriteString(fmt.Sprintf(" :%d := JSON_SERIALIZE(l_deleted_records(%d).", outParamIndex+1, rowIdx+1))
309-
writeQuotedIdentifier(&plsqlBuilder, column)
309+
db.QuoteTo(&plsqlBuilder, column)
310310
plsqlBuilder.WriteString(" RETURNING CLOB);\n")
311311
plsqlBuilder.WriteString(" END IF;\n")
312312
}
@@ -316,7 +316,7 @@ func buildBulkDeletePLSQL(db *gorm.DB) {
316316
stmt.Vars = append(stmt.Vars, sql.Out{Dest: dest})
317317
plsqlBuilder.WriteString(fmt.Sprintf(" IF l_deleted_records.COUNT > %d THEN\n", rowIdx))
318318
plsqlBuilder.WriteString(fmt.Sprintf(" :%d := l_deleted_records(%d).", outParamIndex+1, rowIdx+1))
319-
writeQuotedIdentifier(&plsqlBuilder, column)
319+
db.QuoteTo(&plsqlBuilder, column)
320320
plsqlBuilder.WriteString(";\n")
321321
plsqlBuilder.WriteString(" END IF;\n")
322322
}

oracle/update.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,17 +572,17 @@ func buildUpdatePLSQL(db *gorm.DB) {
572572
if isJSONField(field) {
573573
if isRawMessageField(field) {
574574
plsqlBuilder.WriteString(fmt.Sprintf("l_updated_records(%d).", rowIdx+1))
575-
writeQuotedIdentifier(&plsqlBuilder, column)
575+
db.QuoteTo(&plsqlBuilder, column)
576576
} else {
577577
// serialize JSON so it binds as text
578578
plsqlBuilder.WriteString("JSON_SERIALIZE(")
579579
plsqlBuilder.WriteString(fmt.Sprintf("l_updated_records(%d).", rowIdx+1))
580-
writeQuotedIdentifier(&plsqlBuilder, column)
580+
db.QuoteTo(&plsqlBuilder, column)
581581
plsqlBuilder.WriteString(" RETURNING CLOB)")
582582
}
583583
} else {
584584
plsqlBuilder.WriteString(fmt.Sprintf("l_updated_records(%d).", rowIdx+1))
585-
writeQuotedIdentifier(&plsqlBuilder, column)
585+
db.QuoteTo(&plsqlBuilder, column)
586586
}
587587

588588
plsqlBuilder.WriteString("; END IF;\n")

tests/config_test.go

Lines changed: 146 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -39,65 +39,182 @@
3939
package tests
4040

4141
import (
42+
"errors"
4243
"regexp"
44+
"sort"
4345
"testing"
4446

47+
"github.com/google/uuid"
4548
"github.com/oracle-samples/gorm-oracle/oracle"
4649
"gorm.io/gorm"
50+
"gorm.io/gorm/clause"
51+
"gorm.io/gorm/utils/tests"
4752
)
4853

49-
type Student struct {
50-
ID uint
51-
Name string
54+
type FolderData struct {
55+
ID string `gorm:"primaryKey;column:folder_id"`
56+
Name string `gorm:"column:folder_nm"`
57+
Properties []FolderProperty `gorm:"foreignKey:ID;PRELOAD:false"`
5258
}
5359

54-
func (s Student) TableName() string {
55-
return "STUDENTS"
60+
func (FolderData) TableName() string {
61+
return "folder_data"
5662
}
5763

58-
func TestSkipQuoteIdentifiers(t *testing.T) {
64+
type FolderProperty struct {
65+
Seq uint64 `gorm:"autoIncrement"`
66+
ID string `gorm:"primaryKey;column:folder_id"`
67+
Key string `gorm:"primaryKey;unique"`
68+
Value string
69+
}
70+
71+
func (FolderProperty) TableName() string {
72+
return "folder_property"
73+
}
74+
75+
func TestSkipQuoteIdentifiersMigrator(t *testing.T) {
5976
db, err := openTestDBWithOptions(
6077
&oracle.Config{SkipQuoteIdentifiers: true},
6178
&gorm.Config{Logger: newLogger})
6279
if err != nil {
6380
t.Fatalf("failed to connect database, got error %v", err)
6481
}
6582

66-
db.Migrator().DropTable(&Student{})
67-
db.Migrator().CreateTable(&Student{})
83+
db.Migrator().DropTable(&FolderData{}, &FolderProperty{})
84+
db.Migrator().CreateTable(&FolderData{}, &FolderProperty{})
6885

69-
if !db.Migrator().HasTable(&Student{}) {
70-
t.Errorf("Failed to get table: student")
86+
folderDataTN := "FOLDER_DATA"
87+
if !db.Migrator().HasTable(folderDataTN) {
88+
t.Errorf("Failed to get table: %s", folderDataTN)
7189
}
7290

73-
if !db.Migrator().HasColumn(&Student{}, "ID") {
74-
t.Errorf("Failed to get column: id")
91+
if !db.Migrator().HasColumn(folderDataTN, "FOLDER_ID") {
92+
t.Errorf("Failed to get column: FOLDER_ID")
7593
}
7694

77-
if !db.Migrator().HasColumn(&Student{}, "NAME") {
78-
t.Errorf("Failed to get column: name")
95+
if !db.Migrator().HasColumn(folderDataTN, "FOLDER_NM") {
96+
t.Errorf("Failed to get column: FOLDER_NM")
7997
}
8098

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)
99+
folderPropertyTN := "FOLDER_PROPERTY"
100+
if !db.Migrator().HasTable(folderPropertyTN) {
101+
t.Errorf("Failed to get table: %s", folderPropertyTN)
84102
}
85103

86-
var result Student
87-
if err := db.First(&result).Error; err != nil {
88-
t.Errorf("Failed to query first student, got %v", err)
104+
if !db.Migrator().HasColumn(folderPropertyTN, "SEQ") {
105+
t.Errorf("Failed to get column: SEQ")
89106
}
90107

91-
if result.ID != student.ID {
92-
t.Errorf("id should be %v, but got %v", student.ID, result.ID)
108+
if !db.Migrator().HasColumn(folderPropertyTN, "FOLDER_ID") {
109+
t.Errorf("Failed to get column: FOLDER_ID")
93110
}
94111

95-
if result.Name != student.Name {
96-
t.Errorf("name should be %v, but got %v", student.Name, result.Name)
112+
if !db.Migrator().HasColumn(folderPropertyTN, "KEY") {
113+
t.Errorf("Failed to get column: KEY")
114+
}
115+
116+
if !db.Migrator().HasColumn(folderPropertyTN, "VALUE") {
117+
t.Errorf("Failed to get column: VALUE")
97118
}
98119
}
99120

121+
func TestSkipQuoteIdentifiers(t *testing.T) {
122+
db, err := openTestDBWithOptions(
123+
&oracle.Config{SkipQuoteIdentifiers: true},
124+
&gorm.Config{Logger: newLogger})
125+
if err != nil {
126+
t.Fatalf("failed to connect database, got error %v", err)
127+
}
128+
129+
db.Migrator().DropTable(&FolderData{}, &FolderProperty{})
130+
db.Migrator().CreateTable(&FolderData{}, &FolderProperty{})
131+
132+
id := uuid.New().String()
133+
folder := FolderData{
134+
ID: id,
135+
Name: "My Folder",
136+
Properties: []FolderProperty{
137+
{
138+
ID: id,
139+
Key: "foo1",
140+
Value: "bar1",
141+
},
142+
{
143+
ID: id,
144+
Key: "foo2",
145+
Value: "bar2",
146+
},
147+
},
148+
}
149+
150+
if err := db.Create(&folder).Error; err != nil {
151+
t.Errorf("Failed to insert data, got %v", err)
152+
}
153+
154+
createdFolder := FolderData{}
155+
if err := db.Model(&FolderData{}).Preload("Properties").First(&createdFolder).Error; err != nil {
156+
t.Errorf("Failed to query data, got %v", err)
157+
}
158+
159+
CheckFolderData(t, createdFolder, folder)
160+
161+
createdFolder.Properties[1].Value = "baz1"
162+
createdFolder.Properties = append(createdFolder.Properties, FolderProperty{
163+
ID: id,
164+
Key: "foo3",
165+
Value: "bar3",
166+
})
167+
createdFolder.Properties = append(createdFolder.Properties, FolderProperty{
168+
ID: id,
169+
Key: "foo4",
170+
Value: "bar4",
171+
})
172+
db.Save(&createdFolder)
173+
174+
updatedFolder := FolderData{}
175+
if err := db.Model(&FolderData{}).Preload("Properties").First(&updatedFolder).Error; err != nil {
176+
t.Errorf("Failed to query data, got %v", err)
177+
}
178+
179+
CheckFolderData(t, updatedFolder, createdFolder)
180+
181+
if err := db.Select(clause.Associations).Delete(&createdFolder).Error; err != nil {
182+
t.Errorf("Failed to delete data, got %v", err)
183+
}
184+
185+
result := FolderData{}
186+
if err := db.Where("folder_id = ?", createdFolder.ID).First(&result).Error; err == nil || !errors.Is(err, gorm.ErrRecordNotFound) {
187+
t.Errorf("should returns record not found error, but got %v", err)
188+
}
189+
}
190+
191+
func CheckFolderData(t *testing.T, folderData FolderData, expect FolderData) {
192+
tests.AssertObjEqual(t, folderData, expect, "ID", "Name")
193+
t.Run("Properties", func(t *testing.T) {
194+
if len(folderData.Properties) != len(expect.Properties) {
195+
t.Fatalf("properties should equal, expect: %v, got %v", len(expect.Properties), len(folderData.Properties))
196+
}
197+
198+
sort.Slice(folderData.Properties, func(i, j int) bool {
199+
return folderData.Properties[i].ID > folderData.Properties[j].ID
200+
})
201+
202+
sort.Slice(expect.Properties, func(i, j int) bool {
203+
return expect.Properties[i].ID > expect.Properties[j].ID
204+
})
205+
206+
for idx, property := range folderData.Properties {
207+
tests.AssertObjEqual(t, property, expect.Properties[idx], "Seq", "ID", "Key", "Value")
208+
}
209+
})
210+
}
211+
100212
func TestSkipQuoteIdentifiersSQL(t *testing.T) {
213+
type Student struct {
214+
ID uint
215+
Name string
216+
}
217+
101218
db, err := openTestDBWithOptions(
102219
&oracle.Config{SkipQuoteIdentifiers: true},
103220
&gorm.Config{Logger: newLogger})
@@ -109,34 +226,34 @@ func TestSkipQuoteIdentifiersSQL(t *testing.T) {
109226
insertedStudent := Student{ID: 1, Name: "John"}
110227
result := dryrunDB.Model(&Student{}).Create(&insertedStudent)
111228

112-
if !regexp.MustCompile(`^INSERT INTO STUDENTS \(name,id\) VALUES \(:1,:2\)$`).MatchString(result.Statement.SQL.String()) {
229+
if !regexp.MustCompile(`^INSERT INTO students \(name,id\) VALUES \(:1,:2\)$`).MatchString(result.Statement.SQL.String()) {
113230
t.Errorf("invalid insert SQL, got %v", result.Statement.SQL.String())
114231
}
115232

116233
// Test First
117234
var firstStudent Student
118235
result = dryrunDB.First(&firstStudent)
119236

120-
if !regexp.MustCompile(`^SELECT \* FROM STUDENTS ORDER BY STUDENTS\.id FETCH NEXT 1 ROW ONLY$`).MatchString(result.Statement.SQL.String()) {
237+
if !regexp.MustCompile(`^SELECT \* FROM students ORDER BY students\.id FETCH NEXT 1 ROW ONLY$`).MatchString(result.Statement.SQL.String()) {
121238
t.Fatalf("SQL should include selected names, but got %v", result.Statement.SQL.String())
122239
}
123240

124241
// Test Find
125242
var foundStudent Student
126243
result = dryrunDB.Find(foundStudent, "id = ?", insertedStudent.ID)
127-
if !regexp.MustCompile(`^SELECT \* FROM STUDENTS WHERE id = :1$`).MatchString(result.Statement.SQL.String()) {
244+
if !regexp.MustCompile(`^SELECT \* FROM students WHERE id = :1$`).MatchString(result.Statement.SQL.String()) {
128245
t.Fatalf("SQL should include selected names, but got %v", result.Statement.SQL.String())
129246
}
130247

131248
// Test Save
132249
result = dryrunDB.Save(&Student{ID: 2, Name: "Mary"})
133-
if !regexp.MustCompile(`^UPDATE STUDENTS SET name=:1 WHERE id = :2$`).MatchString(result.Statement.SQL.String()) {
250+
if !regexp.MustCompile(`^UPDATE students SET name=:1 WHERE id = :2$`).MatchString(result.Statement.SQL.String()) {
134251
t.Fatalf("SQL should include selected names, but got %v", result.Statement.SQL.String())
135252
}
136253

137254
// Update with conditions
138255
result = dryrunDB.Model(&Student{}).Where("id = ?", 1).Update("name", "hello")
139-
if !regexp.MustCompile(`^UPDATE STUDENTS SET name=:1 WHERE id = :2$`).MatchString(result.Statement.SQL.String()) {
256+
if !regexp.MustCompile(`^UPDATE students SET name=:1 WHERE id = :2$`).MatchString(result.Statement.SQL.String()) {
140257
t.Fatalf("SQL should include selected names, but got %v", result.Statement.SQL.String())
141258
}
142259
}

0 commit comments

Comments
 (0)