2015-05-16 8 views
6

Avere questa struttura della tabella:Confuso su tipi personalizzati in SQL quando 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'; 

ho questo (non completa) Codice lavorando bene:

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 
} 

Quindi la mia domanda è: Perché è necessario utilizzare il riferimento del puntatore (&eqi.Status) su db.Exec?

Sia sql.NullString e mia abitudine StatusEnum non sono implementate in github.com/go-sql-driver/mysql, quindi perché la differenza?

Se io non uso il riferimento puntatore (eqi.Status), sto ottenendo questo errore (gettando in database/sql/convert.go):

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

Stavo cercando di attuare alcune altre interfacce che ho trovato senza fortuna.

Ho altri tipi personalizzati implementati con interfacce sql.Scanner e sql.driver.Valuer, ma il problema è lo stesso.

stavo indovinando circa struct e il tipo di differenziazione eredità, ma non ho potuto ottenere alcun suggerimento su quello ... :(

Si prega di aiutare a capire cosa sta succedendo. Grazie !!! :)

risposta

4

Si implementa il Valuer interface per il proprio tipo StatusEnum come operante su un *StatusEnum. Pertanto, quando si passa uno come parametro a Exec, ha senso solo come puntatore, poiché solo i puntatori aimplementano Value(), richiedendo una deferenza in linea.

Non si dispone di una definizione per il tipo EmailList in modo da poter suggerire una modifica all'interfaccia Valuer specificata.

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

Questa è la libreria standard implements tipi nullable personalizzati.

+0

Spiacente, ho corretto il codice sostituendo '' 'EmailList''' con' '' StatusEnum'''. Questo è più confuso perché questo codice funziona perfettamente: '' 'v, err: = eqi.Status.Value() \t v, err = (& eqi.Status) .Value()' '' –

+0

Per chiunque entri in e leggendo, questo è perché puoi chiamare un metodo puntatore su un valore non puntatore e prenderà automaticamente l'indirizzo, ma solo se è un metodo non di interfaccia, cioè la variabile è un'interfaccia. https://golang.org/ref/spec#Method_values –