@@ -4,17 +4,20 @@ import (
44 "context"
55 "database/sql/driver"
66 "fmt"
7+ "reflect"
8+ "regexp"
9+ "strings"
710
811 "github.com/godror/godror"
912)
1013
1114var DB godror.Execer // set in tests
1215
1316// EmailList is a Go wrapper for Oracle VARRAY type EMAIL_LIST_ARR.
14- type EmailList []string
17+ type StringList []string
1518
1619// Scan implements sql.Scanner (Oracle -> Go)
17- func (e * EmailList ) Scan (src interface {}) error {
20+ func (e * StringList ) Scan (src interface {}) error {
1821 obj , ok := src .(* godror.Object )
1922 if ! ok {
2023 return fmt .Errorf ("expected *godror.Object, got %T" , src )
@@ -50,8 +53,8 @@ func (e *EmailList) Scan(src interface{}) error {
5053}
5154
5255// Value implements driver.Valuer (Go -> Oracle)
53- func (e EmailList ) Value () (driver.Value , error ) {
54- if e == nil {
56+ func (s StringList ) Value () (driver.Value , error ) {
57+ if s == nil {
5558 return nil , nil
5659 }
5760 if DB == nil {
@@ -60,9 +63,15 @@ func (e EmailList) Value() (driver.Value, error) {
6063
6164 ctx := context .Background ()
6265
63- objType , err := godror .GetObjectType (ctx , DB , "\" email_list_arr\" " )
66+ // Try to detect Oracle type name dynamically via reflection
67+ typeName , err := detectOracleTypeName (s )
6468 if err != nil {
65- return nil , fmt .Errorf ("get object type: %w" , err )
69+ return nil , err
70+ }
71+
72+ objType , err := godror .GetObjectType (ctx , DB , fmt .Sprintf ("\" %s\" " , typeName ))
73+ if err != nil {
74+ return nil , fmt .Errorf ("get object type %q: %w" , typeName , err )
6675 }
6776 defer objType .Close ()
6877
@@ -72,12 +81,37 @@ func (e EmailList) Value() (driver.Value, error) {
7281 }
7382 coll := obj .Collection ()
7483
75- for _ , s := range e {
76- if err := coll .Append (s ); err != nil {
84+ for _ , v := range s {
85+ if err := coll .Append (v ); err != nil {
7786 obj .Close ()
7887 return nil , fmt .Errorf ("append: %w" , err )
7988 }
8089 }
8190
8291 return obj , nil
8392}
93+
94+ // detectOracleTypeName uses reflection to look up the `gorm:"type:..."` tag.
95+ func detectOracleTypeName (value interface {}) (string , error ) {
96+ val := reflect .ValueOf (value )
97+ if val .Kind () == reflect .Ptr {
98+ val = val .Elem ()
99+ }
100+
101+ // walk up the call stack and look for the struct field tag
102+ // (GORM provides the value as part of the struct — this works during model serialization)
103+ rt := reflect .TypeOf (value )
104+ for i := 0 ; i < rt .NumField (); i ++ {
105+ field := rt .Field (i )
106+ if tag := field .Tag .Get ("gorm" ); strings .Contains (tag , "type:" ) {
107+ re := regexp .MustCompile (`type:"?([a-zA-Z0-9_]+)"?` )
108+ match := re .FindStringSubmatch (tag )
109+ if len (match ) > 1 {
110+ return strings .ToUpper (match [1 ]), nil
111+ }
112+ }
113+ }
114+
115+ // fallback
116+ return "" , fmt .Errorf ("cannot detect Oracle type name for %T" , value )
117+ }
0 commit comments