123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- 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
- }
|