Skip to content

Commit 9bc63d2

Browse files
committed
custom datatype varray
1 parent d04b02d commit 9bc63d2

File tree

2 files changed

+59
-127
lines changed

2 files changed

+59
-127
lines changed

oracle/varray.go

Lines changed: 0 additions & 114 deletions
This file was deleted.

tests/varray_test.go

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,65 @@
3939
package tests
4040

4141
import (
42+
"context"
43+
"fmt"
4244
"reflect"
45+
"strings"
4346
"testing"
4447

45-
"github.com/oracle-samples/gorm-oracle/oracle"
48+
"github.com/godror/godror"
49+
"gorm.io/gorm"
50+
"gorm.io/gorm/clause"
4651
)
4752

53+
// custom data type
54+
type StringList []string
55+
56+
// Scan implements sql.Scanner (Oracle -> Go)
57+
func (e *StringList) Scan(src interface{}) error {
58+
obj, ok := src.(*godror.Object)
59+
if !ok {
60+
return fmt.Errorf("expected *godror.Object, got %T", src)
61+
}
62+
defer obj.Close()
63+
64+
coll := obj.Collection()
65+
length, err := coll.Len()
66+
if err != nil {
67+
return fmt.Errorf("get collection length: %w", err)
68+
}
69+
70+
var list []string
71+
for i := 0; i < length; i++ {
72+
var data godror.Data
73+
if err := coll.GetItem(&data, i); err != nil {
74+
return fmt.Errorf("GetItem %d: %w", i, err)
75+
}
76+
val := data.Get()
77+
switch v := val.(type) {
78+
case string:
79+
list = append(list, v)
80+
case []byte:
81+
list = append(list, string(v))
82+
default:
83+
if v != nil {
84+
list = append(list, fmt.Sprint(v))
85+
}
86+
}
87+
}
88+
*e = list
89+
return nil
90+
}
91+
92+
// Implement GormValue interface
93+
func (e StringList) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
94+
if len(e) == 0 {
95+
return gorm.Expr(`"email_list_arr"()`)
96+
}
97+
vals := "'" + strings.Join(e, "','") + "'"
98+
return gorm.Expr(fmt.Sprintf(`"email_list_arr"(%s)`, vals))
99+
}
100+
48101
// Struct mapping to phone_typ object
49102
type Phone struct {
50103
CountryCode string `gorm:"column:country_code"`
@@ -60,8 +113,8 @@ type DeptPhoneList struct {
60113

61114
// Struct for table with email VARRAY
62115
type EmailVarrayTable struct {
63-
ID uint `gorm:"column:ID;primaryKey"`
64-
Emails oracle.StringList `gorm:"column:EMAILS;type:\"email_list_arr\""`
116+
ID uint `gorm:"column:ID;primaryKey"`
117+
Emails StringList `gorm:"column:EMAILS;type:\"email_list_arr\""`
65118
}
66119

67120
func TestStringVarray(t *testing.T) {
@@ -91,13 +144,6 @@ func TestStringVarray(t *testing.T) {
91144
t.Fatalf("Failed to create email_varray_tables: %v", err)
92145
}
93146

94-
// expose raw *sql.DB to oracle package for godror.GetObjectType
95-
sqlDB, err := DB.DB()
96-
if err != nil {
97-
t.Fatalf("cannot get *sql.DB from GORM: %v", err)
98-
}
99-
oracle.DB = sqlDB
100-
101147
// Insert initial data via raw SQL
102148
insertRaw := `INSERT INTO "email_varray_tables" VALUES (1, "email_list_arr"('[email protected]','[email protected]','[email protected]'))`
103149
if err := DB.Exec(insertRaw).Error; err != nil {
@@ -116,20 +162,20 @@ func TestStringVarray(t *testing.T) {
116162

117163
// Update
118164
newEmails := []string{"[email protected]", "[email protected]"}
119-
if err := DB.Model(&got).Update("Emails", newEmails).Error; err != nil {
165+
if err := DB.Model(&got).Update("Emails", StringList(newEmails)).Error; err != nil {
120166
t.Fatalf("Failed to update emails: %v", err)
121167
}
122168
var updated EmailVarrayTable
123169
if err := DB.First(&updated, 1).Error; err != nil {
124170
t.Fatalf("Failed to reload updated EmailVarrayTable: %v", err)
125171
}
126-
if !reflect.DeepEqual(updated.Emails, oracle.StringList(newEmails)) {
172+
if !reflect.DeepEqual(updated.Emails, StringList(newEmails)) {
127173
t.Errorf("String VARRAY update failed: got %v, want %v", updated.Emails, newEmails)
128174
}
129175

130176
// Insert
131177
item := EmailVarrayTable{
132-
ID: 1,
178+
ID: 2,
133179
134180
}
135181
if err := DB.Create(&item).Error; err != nil {

0 commit comments

Comments
 (0)