http urls monitor.

custom_types.go 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright (c) 2012-present The upper.io/db authors. All rights reserved.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining
  4. // a copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to
  8. // permit persons to whom the Software is furnished to do so, subject to
  9. // the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be
  12. // included in all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. package mysql
  22. import (
  23. "database/sql/driver"
  24. "encoding/json"
  25. "errors"
  26. "reflect"
  27. "upper.io/db.v3/lib/sqlbuilder"
  28. )
  29. // JSON represents a MySQL's JSON value:
  30. // https://www.mysql.org/docs/9.6/static/datatype-json.html. JSON
  31. // satisfies sqlbuilder.ScannerValuer.
  32. type JSON struct {
  33. V interface{}
  34. }
  35. // MarshalJSON encodes the wrapper value as JSON.
  36. func (j JSON) MarshalJSON() ([]byte, error) {
  37. return json.Marshal(j.V)
  38. }
  39. // UnmarshalJSON decodes the given JSON into the wrapped value.
  40. func (j *JSON) UnmarshalJSON(b []byte) error {
  41. var v interface{}
  42. if err := json.Unmarshal(b, &v); err != nil {
  43. return err
  44. }
  45. j.V = v
  46. return nil
  47. }
  48. // Scan satisfies the sql.Scanner interface.
  49. func (j *JSON) Scan(src interface{}) error {
  50. if src == nil {
  51. j.V = nil
  52. return nil
  53. }
  54. b, ok := src.([]byte)
  55. if !ok {
  56. return errors.New("Scan source was not []bytes")
  57. }
  58. if err := json.Unmarshal(b, &j.V); err != nil {
  59. return err
  60. }
  61. return nil
  62. }
  63. // Value satisfies the driver.Valuer interface.
  64. func (j JSON) Value() (driver.Value, error) {
  65. // See https://github.com/lib/pq/issues/528#issuecomment-257197239 on why are
  66. // we returning string instead of []byte.
  67. if j.V == nil {
  68. return nil, nil
  69. }
  70. if v, ok := j.V.(json.RawMessage); ok {
  71. return string(v), nil
  72. }
  73. b, err := json.Marshal(j.V)
  74. if err != nil {
  75. return nil, err
  76. }
  77. return string(b), nil
  78. }
  79. // JSONMap represents a map of interfaces with string keys
  80. // (`map[string]interface{}`) that is compatible with MySQL's JSON type.
  81. // JSONMap satisfies sqlbuilder.ScannerValuer.
  82. type JSONMap map[string]interface{}
  83. // Value satisfies the driver.Valuer interface.
  84. func (m JSONMap) Value() (driver.Value, error) {
  85. return JSONValue(m)
  86. }
  87. // Scan satisfies the sql.Scanner interface.
  88. func (m *JSONMap) Scan(src interface{}) error {
  89. *m = map[string]interface{}(nil)
  90. return ScanJSON(m, src)
  91. }
  92. // JSONArray represents an array of any type (`[]interface{}`) that is
  93. // compatible with MySQL's JSON type. JSONArray satisfies
  94. // sqlbuilder.ScannerValuer.
  95. type JSONArray []interface{}
  96. // Value satisfies the driver.Valuer interface.
  97. func (a JSONArray) Value() (driver.Value, error) {
  98. return JSONValue(a)
  99. }
  100. // Scan satisfies the sql.Scanner interface.
  101. func (a *JSONArray) Scan(src interface{}) error {
  102. return ScanJSON(a, src)
  103. }
  104. // JSONValue takes an interface and provides a driver.Value that can be
  105. // stored as a JSON column.
  106. func JSONValue(i interface{}) (driver.Value, error) {
  107. v := JSON{i}
  108. return v.Value()
  109. }
  110. // ScanJSON decodes a JSON byte stream into the passed dst value.
  111. func ScanJSON(dst interface{}, src interface{}) error {
  112. v := JSON{dst}
  113. return v.Scan(src)
  114. }
  115. // EncodeJSON is deprecated and going to be removed. Use ScanJSON instead.
  116. func EncodeJSON(i interface{}) (driver.Value, error) {
  117. return JSONValue(i)
  118. }
  119. // DecodeJSON is deprecated and going to be removed. Use JSONValue instead.
  120. func DecodeJSON(dst interface{}, src interface{}) error {
  121. return ScanJSON(dst, src)
  122. }
  123. // JSONConverter provides a helper method WrapValue that satisfies
  124. // sqlbuilder.ValueWrapper, can be used to encode Go structs into JSON
  125. // MySQL types and vice versa.
  126. //
  127. // Example:
  128. //
  129. // type MyCustomStruct struct {
  130. // ID int64 `db:"id" json:"id"`
  131. // Name string `db:"name" json:"name"`
  132. // ...
  133. // mysql.JSONConverter
  134. // }
  135. type JSONConverter struct {
  136. }
  137. // WrapValue satisfies sqlbuilder.ValueWrapper
  138. func (obj *JSONConverter) WrapValue(src interface{}) interface{} {
  139. return &JSON{src}
  140. }
  141. func autoWrap(elem reflect.Value, v interface{}) interface{} {
  142. kind := elem.Kind()
  143. if kind == reflect.Invalid {
  144. return v
  145. }
  146. if elem.Type().Implements(sqlbuilder.ScannerType) {
  147. return v
  148. }
  149. if elem.Type().Implements(sqlbuilder.ValuerType) {
  150. return v
  151. }
  152. if elem.Type().Implements(sqlbuilder.ValueWrapperType) {
  153. if elem.Type().Kind() == reflect.Ptr {
  154. w := reflect.ValueOf(v)
  155. if w.Kind() == reflect.Ptr {
  156. z := reflect.Zero(w.Elem().Type())
  157. w.Elem().Set(z)
  158. return &JSON{v}
  159. }
  160. }
  161. vw := elem.Interface().(sqlbuilder.ValueWrapper)
  162. return vw.WrapValue(elem.Interface())
  163. }
  164. switch kind {
  165. case reflect.Ptr:
  166. return autoWrap(elem.Elem(), v)
  167. case reflect.Slice:
  168. return &JSON{v}
  169. case reflect.Map:
  170. if reflect.TypeOf(v).Kind() == reflect.Ptr {
  171. w := reflect.ValueOf(v)
  172. z := reflect.New(w.Elem().Type())
  173. w.Elem().Set(z.Elem())
  174. }
  175. return &JSON{v}
  176. }
  177. return v
  178. }
  179. // Type checks.
  180. var (
  181. _ sqlbuilder.ValueWrapper = &JSONConverter{}
  182. _ sqlbuilder.ScannerValuer = &JSONMap{}
  183. _ sqlbuilder.ScannerValuer = &JSONArray{}
  184. )