types.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package types
  2. import (
  3. "bytes"
  4. "compress/gzip"
  5. "database/sql/driver"
  6. "encoding/json"
  7. "errors"
  8. "io/ioutil"
  9. )
  10. // GzippedText is a []byte which transparently gzips data being submitted to
  11. // a database and ungzips data being Scanned from a database.
  12. type GzippedText []byte
  13. // Value implements the driver.Valuer interface, gzipping the raw value of
  14. // this GzippedText.
  15. func (g GzippedText) Value() (driver.Value, error) {
  16. b := make([]byte, 0, len(g))
  17. buf := bytes.NewBuffer(b)
  18. w := gzip.NewWriter(buf)
  19. w.Write(g)
  20. w.Close()
  21. return buf.Bytes(), nil
  22. }
  23. // Scan implements the sql.Scanner interface, ungzipping the value coming off
  24. // the wire and storing the raw result in the GzippedText.
  25. func (g *GzippedText) Scan(src interface{}) error {
  26. var source []byte
  27. switch src := src.(type) {
  28. case string:
  29. source = []byte(src)
  30. case []byte:
  31. source = src
  32. default:
  33. return errors.New("Incompatible type for GzippedText")
  34. }
  35. reader, err := gzip.NewReader(bytes.NewReader(source))
  36. if err != nil {
  37. return err
  38. }
  39. defer reader.Close()
  40. b, err := ioutil.ReadAll(reader)
  41. if err != nil {
  42. return err
  43. }
  44. *g = GzippedText(b)
  45. return nil
  46. }
  47. // JSONText is a json.RawMessage, which is a []byte underneath.
  48. // Value() validates the json format in the source, and returns an error if
  49. // the json is not valid. Scan does no validation. JSONText additionally
  50. // implements `Unmarshal`, which unmarshals the json within to an interface{}
  51. type JSONText json.RawMessage
  52. var emptyJSON = JSONText("{}")
  53. // MarshalJSON returns the *j as the JSON encoding of j.
  54. func (j JSONText) MarshalJSON() ([]byte, error) {
  55. if len(j) == 0 {
  56. return emptyJSON, nil
  57. }
  58. return j, nil
  59. }
  60. // UnmarshalJSON sets *j to a copy of data
  61. func (j *JSONText) UnmarshalJSON(data []byte) error {
  62. if j == nil {
  63. return errors.New("JSONText: UnmarshalJSON on nil pointer")
  64. }
  65. *j = append((*j)[0:0], data...)
  66. return nil
  67. }
  68. // Value returns j as a value. This does a validating unmarshal into another
  69. // RawMessage. If j is invalid json, it returns an error.
  70. func (j JSONText) Value() (driver.Value, error) {
  71. var m json.RawMessage
  72. var err = j.Unmarshal(&m)
  73. if err != nil {
  74. return []byte{}, err
  75. }
  76. return []byte(j), nil
  77. }
  78. // Scan stores the src in *j. No validation is done.
  79. func (j *JSONText) Scan(src interface{}) error {
  80. var source []byte
  81. switch t := src.(type) {
  82. case string:
  83. source = []byte(t)
  84. case []byte:
  85. if len(t) == 0 {
  86. source = emptyJSON
  87. } else {
  88. source = t
  89. }
  90. case nil:
  91. *j = emptyJSON
  92. default:
  93. return errors.New("Incompatible type for JSONText")
  94. }
  95. *j = append((*j)[0:0], source...)
  96. return nil
  97. }
  98. // Unmarshal unmarshal's the json in j to v, as in json.Unmarshal.
  99. func (j *JSONText) Unmarshal(v interface{}) error {
  100. if len(*j) == 0 {
  101. *j = emptyJSON
  102. }
  103. return json.Unmarshal([]byte(*j), v)
  104. }
  105. // String supports pretty printing for JSONText types.
  106. func (j JSONText) String() string {
  107. return string(j)
  108. }
  109. // NullJSONText represents a JSONText that may be null.
  110. // NullJSONText implements the scanner interface so
  111. // it can be used as a scan destination, similar to NullString.
  112. type NullJSONText struct {
  113. JSONText
  114. Valid bool // Valid is true if JSONText is not NULL
  115. }
  116. // Scan implements the Scanner interface.
  117. func (n *NullJSONText) Scan(value interface{}) error {
  118. if value == nil {
  119. n.JSONText, n.Valid = emptyJSON, false
  120. return nil
  121. }
  122. n.Valid = true
  123. return n.JSONText.Scan(value)
  124. }
  125. // Value implements the driver Valuer interface.
  126. func (n NullJSONText) Value() (driver.Value, error) {
  127. if !n.Valid {
  128. return nil, nil
  129. }
  130. return n.JSONText.Value()
  131. }
  132. // BitBool is an implementation of a bool for the MySQL type BIT(1).
  133. // This type allows you to avoid wasting an entire byte for MySQL's boolean type TINYINT.
  134. type BitBool bool
  135. // Value implements the driver.Valuer interface,
  136. // and turns the BitBool into a bitfield (BIT(1)) for MySQL storage.
  137. func (b BitBool) Value() (driver.Value, error) {
  138. if b {
  139. return []byte{1}, nil
  140. }
  141. return []byte{0}, nil
  142. }
  143. // Scan implements the sql.Scanner interface,
  144. // and turns the bitfield incoming from MySQL into a BitBool
  145. func (b *BitBool) Scan(src interface{}) error {
  146. v, ok := src.([]byte)
  147. if !ok {
  148. return errors.New("bad []byte type assertion")
  149. }
  150. *b = v[0] == 1
  151. return nil
  152. }