2015-05-16 7 views
6

Mając tę ​​strukturę tabeli:Confused o niestandardowych typów w SQL po sql.DB.Exec

CREATE TABLE `tableName` (
    `Id` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    `Status` enum('pending','rejected','sent','invalid') NOT NULL, 
    `Body` varchar(255) NULL 
) ENGINE='MyISAM' COLLATE 'utf8_general_ci'; 

mam to (nie zakończyć) Kod działa dobrze:

type StatusEnum string 

const (
    STATUS_PENDING StatusEnum = "pending" 
    STATUS_REJECTED StatusEnum = "rejected" 
    STATUS_SENT  StatusEnum = "sent" 
    STATUS_INVALID StatusEnum = "invalid" 
) 

func (s *StatusEnum) Scan(src interface{}) error { 
    if src == nil { 
     return errors.New("This field cannot be NULL") 
    } 

    if stringStatus, ok := src.([]byte); ok { 
     *s = StatusEnum(string(stringStatus[:])) 

     return nil 
    } 

    return errors.New("Cannot convert enum to string") 
} 

func (s *StatusEnum) Value() (driver.Value, error) { 
    return []byte(*s), nil 
} 

type EmailQueue struct { 
    Id  uint64 
    Status StatusEnum 
    Body  sql.NullString 
} 

func Save (db *sql.DB) error { 
    _, err = db.Exec(
     "UPDATE `tableName` SET `Status` = ?, `Body` = ? WHERE `id` = ?", 
     &eqi.Status, 
     eqi.Body, 
     eqi.Id, 
    ) 

    return err 
} 

więc moje pytanie to: Dlaczego muszę używać wskaźnika odniesienia (&eqi.Status) na db.Exec?

Zarówno sql.NullString i mój zwyczaj StatusEnum nie są realizowane w github.com/go-sql-driver/mysql, więc dlaczego różnica?

Jeśli nie używam odniesienia wskaźnika (eqi.Status), dostaję ten błąd (rzucanie w database/sql/convert.go):

sql: converting Exec argument #0's type: unsupported type emailqueue.StatusEnum, a string 

starałem się wdrożyć kilka innych interfejsów mam ze nie znaleziono szczęście.

Mam inne typy niestandardowe zaimplementowane z interfejsami sql.Scanner i sql.driver.Valuer, ale problem jest taki sam.

Byłem zgadywania o struct i różnicowanie typu dziedziczenia, ale nie mogłem dostać żadnego śladu na tym, że ... :(

Proszę pomóc zrozumieć, co się dzieje. Dzięki !!! :)

Odpowiedz

4

Użytkownik implementuje Valuer interface dla swojego typu StatusEnum jako działający pod numerem *StatusEnum. Dlatego, kiedy przekazujesz jeden jako parametr do Exec, ma sens tylko jako wskaźnik, a jedynie wskaźniki do StatusEnum implementują Value(), wymagając wstawienia w linii.

Nie masz definicji dla typu EmailList, więc mogę zasugerować zmianę podanego interfejsu Valuer.

func (s StatusEnum) Value() (driver.Value, error) { 
    return []byte(s), nil 
} 

Jest to standardowy typ zerowania biblioteki implements.

+0

Naprawiono kod zastępujący '' 'EmailList'''' '' StatusEnum'''. Jest to jednak bardziej mylące, ponieważ ten kod działa doskonale: '' ', err: = eqi.Status.Value() \t v, err = (& eqi.Status) .Value()' '' –

+0

Dla każdego, kto przyjdzie i czytanie, ponieważ można wywołać metodę wskaźnika na wartości innej niż wskaźnik i automatycznie pobierze adres, ale tylko wtedy, gdy jest to metoda bez interfejsu, tzn. zmienna jest interfejsem. https://golang.org/ref/spec#Method_values –

Powiązane problemy