Permalink
append is already returning the correct type here.
package types | |
import ( | |
"bytes" | |
"compress/gzip" | |
"database/sql/driver" | |
"encoding/json" | |
"errors" | |
"io/ioutil" | |
) | |
// GzippedText is a []byte which transparently gzips data being submitted to | |
// a database and ungzips data being Scanned from a database. | |
type GzippedText []byte | |
// Value implements the driver.Valuer interface, gzipping the raw value of | |
// this GzippedText. | |
func (g GzippedText) Value() (driver.Value, error) { | |
b := make([]byte, 0, len(g)) | |
buf := bytes.NewBuffer(b) | |
w := gzip.NewWriter(buf) | |
w.Write(g) | |
w.Close() | |
return buf.Bytes(), nil | |
} | |
// Scan implements the sql.Scanner interface, ungzipping the value coming off | |
// the wire and storing the raw result in the GzippedText. | |
func (g *GzippedText) Scan(src interface{}) error { | |
var source []byte | |
switch src := src.(type) { | |
case string: | |
source = []byte(src) | |
case []byte: | |
source = src | |
default: | |
return errors.New("Incompatible type for GzippedText") | |
} | |
reader, err := gzip.NewReader(bytes.NewReader(source)) | |
if err != nil { | |
return err | |
} | |
defer reader.Close() | |
b, err := ioutil.ReadAll(reader) | |
if err != nil { | |
return err | |
} | |
*g = GzippedText(b) | |
return nil | |
} | |
// JSONText is a json.RawMessage, which is a []byte underneath. | |
// Value() validates the json format in the source, and returns an error if | |
// the json is not valid. Scan does no validation. JSONText additionally | |
// implements `Unmarshal`, which unmarshals the json within to an interface{} | |
type JSONText json.RawMessage | |
var emptyJSON = JSONText("{}") | |
// MarshalJSON returns the *j as the JSON encoding of j. | |
func (j JSONText) MarshalJSON() ([]byte, error) { | |
if len(j) == 0 { | |
return emptyJSON, nil | |
} | |
return j, nil | |
} | |
// UnmarshalJSON sets *j to a copy of data | |
func (j *JSONText) UnmarshalJSON(data []byte) error { | |
if j == nil { | |
return errors.New("JSONText: UnmarshalJSON on nil pointer") | |
} | |
*j = append((*j)[0:0], data...) | |
return nil | |
} | |
// Value returns j as a value. This does a validating unmarshal into another | |
// RawMessage. If j is invalid json, it returns an error. | |
func (j JSONText) Value() (driver.Value, error) { | |
var m json.RawMessage | |
var err = j.Unmarshal(&m) | |
if err != nil { | |
return []byte{}, err | |
} | |
return []byte(j), nil | |
} | |
// Scan stores the src in *j. No validation is done. | |
func (j *JSONText) Scan(src interface{}) error { | |
var source []byte | |
switch t := src.(type) { | |
case string: | |
source = []byte(t) | |
case []byte: | |
if len(t) == 0 { | |
source = emptyJSON | |
} else { | |
source = t | |
} | |
case nil: | |
*j = emptyJSON | |
default: | |
return errors.New("Incompatible type for JSONText") | |
} | |
*j = append((*j)[0:0], source...) | |
return nil | |
} | |
// Unmarshal unmarshal's the json in j to v, as in json.Unmarshal. | |
func (j *JSONText) Unmarshal(v interface{}) error { | |
if len(*j) == 0 { | |
*j = emptyJSON | |
} | |
return json.Unmarshal([]byte(*j), v) | |
} | |
// String supports pretty printing for JSONText types. | |
func (j JSONText) String() string { | |
return string(j) | |
} | |
// NullJSONText represents a JSONText that may be null. | |
// NullJSONText implements the scanner interface so | |
// it can be used as a scan destination, similar to NullString. | |
type NullJSONText struct { | |
JSONText | |
Valid bool // Valid is true if JSONText is not NULL | |
} | |
// Scan implements the Scanner interface. | |
func (n *NullJSONText) Scan(value interface{}) error { | |
if value == nil { | |
n.JSONText, n.Valid = emptyJSON, false | |
return nil | |
} | |
n.Valid = true | |
return n.JSONText.Scan(value) | |
} | |
// Value implements the driver Valuer interface. | |
func (n NullJSONText) Value() (driver.Value, error) { | |
if !n.Valid { | |
return nil, nil | |
} | |
return n.JSONText.Value() | |
} | |
// BitBool is an implementation of a bool for the MySQL type BIT(1). | |
// This type allows you to avoid wasting an entire byte for MySQL's boolean type TINYINT. | |
type BitBool bool | |
// Value implements the driver.Valuer interface, | |
// and turns the BitBool into a bitfield (BIT(1)) for MySQL storage. | |
func (b BitBool) Value() (driver.Value, error) { | |
if b { | |
return []byte{1}, nil | |
} | |
return []byte{0}, nil | |
} | |
// Scan implements the sql.Scanner interface, | |
// and turns the bitfield incoming from MySQL into a BitBool | |
func (b *BitBool) Scan(src interface{}) error { | |
v, ok := src.([]byte) | |
if !ok { | |
return errors.New("bad []byte type assertion") | |
} | |
*b = v[0] == 1 | |
return nil | |
} |