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
2 changes: 2 additions & 0 deletions oracle/clause_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ func shouldIncludeColumn(stmt *gorm.Statement, columnName string) bool {
stmt.Schema.PrioritizedPrimaryField.AutoIncrement &&
stmt.Schema.PrioritizedPrimaryField.DBName == columnName {
return false
} else if stmt.Schema.LookUpField(columnName).AutoIncrement {
return false
}
return true
}
Expand Down
10 changes: 7 additions & 3 deletions oracle/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ func buildBulkMergePLSQL(db *gorm.DB, createValues clause.Values, onConflictClau
schema.PrioritizedPrimaryField.AutoIncrement &&
strings.EqualFold(schema.PrioritizedPrimaryField.DBName, column.Name) {
isAutoIncrement = true
} else if stmt.Schema.LookUpField(column.Name).AutoIncrement {
isAutoIncrement = true
}

if !isConflictColumn && !isAutoIncrement {
Expand Down Expand Up @@ -520,7 +522,7 @@ func buildBulkMergePLSQL(db *gorm.DB, createValues clause.Values, onConflictClau
" IF l_affected_records.COUNT > %d THEN :%d := l_affected_records(%d).",
rowIdx, outParamIndex+1, rowIdx+1,
))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
plsqlBuilder.WriteString("; END IF;\n")
} else {
// datatypes.JSON (text-based) -> serialize to CLOB
Expand All @@ -529,13 +531,13 @@ func buildBulkMergePLSQL(db *gorm.DB, createValues clause.Values, onConflictClau
" IF l_affected_records.COUNT > %d THEN :%d := JSON_SERIALIZE(l_affected_records(%d).",
rowIdx, outParamIndex+1, rowIdx+1,
))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
plsqlBuilder.WriteString(" RETURNING CLOB); END IF;\n")
}
} else {
stmt.Vars = append(stmt.Vars, sql.Out{Dest: createTypedDestination(field)})
plsqlBuilder.WriteString(fmt.Sprintf(" IF l_affected_records.COUNT > %d THEN :%d := l_affected_records(%d).", rowIdx, outParamIndex+1, rowIdx+1))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
plsqlBuilder.WriteString("; END IF;\n")
}
outParamIndex++
Expand Down Expand Up @@ -696,6 +698,8 @@ func shouldIncludeColumnInInsert(stmt *gorm.Statement, columnName string) bool {
stmt.Schema.PrioritizedPrimaryField.AutoIncrement &&
strings.EqualFold(stmt.Schema.PrioritizedPrimaryField.DBName, columnName) {
return false
} else if stmt.Schema.LookUpField(columnName).AutoIncrement {
return false
}
return true
}
Expand Down
6 changes: 3 additions & 3 deletions oracle/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,14 +299,14 @@ func buildBulkDeletePLSQL(db *gorm.DB) {
" IF l_deleted_records.COUNT > %d THEN :%d := l_deleted_records(%d).",
rowIdx, outParamIndex+1, rowIdx+1,
))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
plsqlBuilder.WriteString("; END IF;\n")
} else {
// JSON -> text bind
stmt.Vars = append(stmt.Vars, sql.Out{Dest: new(string)})
plsqlBuilder.WriteString(fmt.Sprintf(" IF l_deleted_records.COUNT > %d THEN\n", rowIdx))
plsqlBuilder.WriteString(fmt.Sprintf(" :%d := JSON_SERIALIZE(l_deleted_records(%d).", outParamIndex+1, rowIdx+1))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
plsqlBuilder.WriteString(" RETURNING CLOB);\n")
plsqlBuilder.WriteString(" END IF;\n")
}
Expand All @@ -316,7 +316,7 @@ func buildBulkDeletePLSQL(db *gorm.DB) {
stmt.Vars = append(stmt.Vars, sql.Out{Dest: dest})
plsqlBuilder.WriteString(fmt.Sprintf(" IF l_deleted_records.COUNT > %d THEN\n", rowIdx))
plsqlBuilder.WriteString(fmt.Sprintf(" :%d := l_deleted_records(%d).", outParamIndex+1, rowIdx+1))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
plsqlBuilder.WriteString(";\n")
plsqlBuilder.WriteString(" END IF;\n")
}
Expand Down
6 changes: 3 additions & 3 deletions oracle/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,17 +572,17 @@ func buildUpdatePLSQL(db *gorm.DB) {
if isJSONField(field) {
if isRawMessageField(field) {
plsqlBuilder.WriteString(fmt.Sprintf("l_updated_records(%d).", rowIdx+1))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
} else {
// serialize JSON so it binds as text
plsqlBuilder.WriteString("JSON_SERIALIZE(")
plsqlBuilder.WriteString(fmt.Sprintf("l_updated_records(%d).", rowIdx+1))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
plsqlBuilder.WriteString(" RETURNING CLOB)")
}
} else {
plsqlBuilder.WriteString(fmt.Sprintf("l_updated_records(%d).", rowIdx+1))
writeQuotedIdentifier(&plsqlBuilder, column)
db.QuoteTo(&plsqlBuilder, column)
}

plsqlBuilder.WriteString("; END IF;\n")
Expand Down
65 changes: 65 additions & 0 deletions tests/associations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@
package tests

import (
"errors"
"strings"
"testing"

"github.com/google/uuid"
. "github.com/oracle-samples/gorm-oracle/tests/utils"

"gorm.io/gorm"
Expand Down Expand Up @@ -543,3 +545,66 @@ func TestBasicManyToManyAssociation(t *testing.T) {

AssertAssociationCount(t, user, "Languages", 0, "after clear")
}

func TestSaveAssociationWithAutoIncrementField(t *testing.T) {
DB.Migrator().DropTable(&FolderData{}, &FolderProperty{})
DB.Migrator().CreateTable(&FolderData{}, &FolderProperty{})

id := uuid.New().String()
folder := FolderData{
ID: id,
Name: "My Folder",
Properties: []FolderProperty{
{
ID: id,
Key: "foo1",
Value: "bar1",
},
{
ID: id,
Key: "foo2",
Value: "bar2",
},
},
}

if err := DB.Create(&folder).Error; err != nil {
t.Errorf("Failed to insert data, got %v", err)
}

createdFolder := FolderData{}
if err := DB.Model(&FolderData{}).Preload("Properties").First(&createdFolder).Error; err != nil {
t.Errorf("Failed to query data, got %v", err)
}

CheckFolderData(t, createdFolder, folder)

createdFolder.Properties[1].Value = "baz1"
createdFolder.Properties = append(createdFolder.Properties, FolderProperty{
ID: id,
Key: "foo3",
Value: "bar3",
})
createdFolder.Properties = append(createdFolder.Properties, FolderProperty{
ID: id,
Key: "foo4",
Value: "bar4",
})
DB.Save(&createdFolder)

updatedFolder := FolderData{}
if err := DB.Model(&FolderData{}).Preload("Properties").First(&updatedFolder).Error; err != nil {
t.Errorf("Failed to query data, got %v", err)
}

CheckFolderData(t, updatedFolder, createdFolder)

if err := DB.Select(clause.Associations).Delete(&createdFolder).Error; err != nil {
t.Errorf("Failed to delete data, got %v", err)
}

result := FolderData{}
if err := DB.Where("\"folder_id\" = ?", createdFolder.ID).First(&result).Error; err == nil || !errors.Is(err, gorm.ErrRecordNotFound) {
t.Errorf("should returns record not found error, but got %v", err)
}
}
21 changes: 21 additions & 0 deletions tests/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,3 +357,24 @@ func db(unscoped bool) *gorm.DB {
return DB
}
}

func CheckFolderData(t *testing.T, folderData FolderData, expect FolderData) {
tests.AssertObjEqual(t, folderData, expect, "ID", "Name")
t.Run("Properties", func(t *testing.T) {
if len(folderData.Properties) != len(expect.Properties) {
t.Fatalf("properties should equal, expect: %v, got %v", len(expect.Properties), len(folderData.Properties))
}

sort.Slice(folderData.Properties, func(i, j int) bool {
return folderData.Properties[i].ID > folderData.Properties[j].ID
})

sort.Slice(expect.Properties, func(i, j int) bool {
return expect.Properties[i].ID > expect.Properties[j].ID
})

for idx, property := range folderData.Properties {
tests.AssertObjEqual(t, property, expect.Properties[idx], "Seq", "ID", "Key", "Value")
}
})
}
13 changes: 13 additions & 0 deletions tests/utils/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,16 @@ type Child struct {
ParentID *uint
Parent *Parent
}

type FolderProperty struct {
Seq uint64 `gorm:"autoIncrement"`
ID string `gorm:"primaryKey;column:folder_id"`
Key string `gorm:"primaryKey;unique"`
Value string
}

type FolderData struct {
ID string `gorm:"primaryKey;column:folder_id"`
Name string `gorm:"column:folder_nm"`
Properties []FolderProperty `gorm:"foreignKey:ID;PRELOAD:false"`
}
Loading