You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

300 lines
6.6 KiB

  1. // Copyright 2015 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package bigquery
  15. import (
  16. "bytes"
  17. "encoding/json"
  18. "fmt"
  19. "reflect"
  20. "strconv"
  21. "time"
  22. "cloud.google.com/go/civil"
  23. )
  24. // NullInt64 represents a BigQuery INT64 that may be NULL.
  25. type NullInt64 struct {
  26. Int64 int64
  27. Valid bool // Valid is true if Int64 is not NULL.
  28. }
  29. func (n NullInt64) String() string { return nullstr(n.Valid, n.Int64) }
  30. // NullString represents a BigQuery STRING that may be NULL.
  31. type NullString struct {
  32. StringVal string
  33. Valid bool // Valid is true if StringVal is not NULL.
  34. }
  35. func (n NullString) String() string { return nullstr(n.Valid, n.StringVal) }
  36. // NullFloat64 represents a BigQuery FLOAT64 that may be NULL.
  37. type NullFloat64 struct {
  38. Float64 float64
  39. Valid bool // Valid is true if Float64 is not NULL.
  40. }
  41. func (n NullFloat64) String() string { return nullstr(n.Valid, n.Float64) }
  42. // NullBool represents a BigQuery BOOL that may be NULL.
  43. type NullBool struct {
  44. Bool bool
  45. Valid bool // Valid is true if Bool is not NULL.
  46. }
  47. func (n NullBool) String() string { return nullstr(n.Valid, n.Bool) }
  48. // NullTimestamp represents a BigQuery TIMESTAMP that may be null.
  49. type NullTimestamp struct {
  50. Timestamp time.Time
  51. Valid bool // Valid is true if Time is not NULL.
  52. }
  53. func (n NullTimestamp) String() string { return nullstr(n.Valid, n.Timestamp) }
  54. // NullDate represents a BigQuery DATE that may be null.
  55. type NullDate struct {
  56. Date civil.Date
  57. Valid bool // Valid is true if Date is not NULL.
  58. }
  59. func (n NullDate) String() string { return nullstr(n.Valid, n.Date) }
  60. // NullTime represents a BigQuery TIME that may be null.
  61. type NullTime struct {
  62. Time civil.Time
  63. Valid bool // Valid is true if Time is not NULL.
  64. }
  65. func (n NullTime) String() string {
  66. if !n.Valid {
  67. return "<null>"
  68. }
  69. return CivilTimeString(n.Time)
  70. }
  71. // NullDateTime represents a BigQuery DATETIME that may be null.
  72. type NullDateTime struct {
  73. DateTime civil.DateTime
  74. Valid bool // Valid is true if DateTime is not NULL.
  75. }
  76. func (n NullDateTime) String() string {
  77. if !n.Valid {
  78. return "<null>"
  79. }
  80. return CivilDateTimeString(n.DateTime)
  81. }
  82. func (n NullInt64) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Int64) }
  83. func (n NullFloat64) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Float64) }
  84. func (n NullBool) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Bool) }
  85. func (n NullString) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.StringVal) }
  86. func (n NullTimestamp) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Timestamp) }
  87. func (n NullDate) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Date) }
  88. func (n NullTime) MarshalJSON() ([]byte, error) {
  89. if !n.Valid {
  90. return jsonNull, nil
  91. }
  92. return []byte(`"` + CivilTimeString(n.Time) + `"`), nil
  93. }
  94. func (n NullDateTime) MarshalJSON() ([]byte, error) {
  95. if !n.Valid {
  96. return jsonNull, nil
  97. }
  98. return []byte(`"` + CivilDateTimeString(n.DateTime) + `"`), nil
  99. }
  100. func nullstr(valid bool, v interface{}) string {
  101. if !valid {
  102. return "NULL"
  103. }
  104. return fmt.Sprint(v)
  105. }
  106. var jsonNull = []byte("null")
  107. func nulljson(valid bool, v interface{}) ([]byte, error) {
  108. if !valid {
  109. return jsonNull, nil
  110. }
  111. return json.Marshal(v)
  112. }
  113. func (n *NullInt64) UnmarshalJSON(b []byte) error {
  114. n.Valid = false
  115. n.Int64 = 0
  116. if bytes.Equal(b, jsonNull) {
  117. return nil
  118. }
  119. if err := json.Unmarshal(b, &n.Int64); err != nil {
  120. return err
  121. }
  122. n.Valid = true
  123. return nil
  124. }
  125. func (n *NullFloat64) UnmarshalJSON(b []byte) error {
  126. n.Valid = false
  127. n.Float64 = 0
  128. if bytes.Equal(b, jsonNull) {
  129. return nil
  130. }
  131. if err := json.Unmarshal(b, &n.Float64); err != nil {
  132. return err
  133. }
  134. n.Valid = true
  135. return nil
  136. }
  137. func (n *NullBool) UnmarshalJSON(b []byte) error {
  138. n.Valid = false
  139. n.Bool = false
  140. if bytes.Equal(b, jsonNull) {
  141. return nil
  142. }
  143. if err := json.Unmarshal(b, &n.Bool); err != nil {
  144. return err
  145. }
  146. n.Valid = true
  147. return nil
  148. }
  149. func (n *NullString) UnmarshalJSON(b []byte) error {
  150. n.Valid = false
  151. n.StringVal = ""
  152. if bytes.Equal(b, jsonNull) {
  153. return nil
  154. }
  155. if err := json.Unmarshal(b, &n.StringVal); err != nil {
  156. return err
  157. }
  158. n.Valid = true
  159. return nil
  160. }
  161. func (n *NullTimestamp) UnmarshalJSON(b []byte) error {
  162. n.Valid = false
  163. n.Timestamp = time.Time{}
  164. if bytes.Equal(b, jsonNull) {
  165. return nil
  166. }
  167. if err := json.Unmarshal(b, &n.Timestamp); err != nil {
  168. return err
  169. }
  170. n.Valid = true
  171. return nil
  172. }
  173. func (n *NullDate) UnmarshalJSON(b []byte) error {
  174. n.Valid = false
  175. n.Date = civil.Date{}
  176. if bytes.Equal(b, jsonNull) {
  177. return nil
  178. }
  179. if err := json.Unmarshal(b, &n.Date); err != nil {
  180. return err
  181. }
  182. n.Valid = true
  183. return nil
  184. }
  185. func (n *NullTime) UnmarshalJSON(b []byte) error {
  186. n.Valid = false
  187. n.Time = civil.Time{}
  188. if bytes.Equal(b, jsonNull) {
  189. return nil
  190. }
  191. s, err := strconv.Unquote(string(b))
  192. if err != nil {
  193. return err
  194. }
  195. t, err := civil.ParseTime(s)
  196. if err != nil {
  197. return err
  198. }
  199. n.Time = t
  200. n.Valid = true
  201. return nil
  202. }
  203. func (n *NullDateTime) UnmarshalJSON(b []byte) error {
  204. n.Valid = false
  205. n.DateTime = civil.DateTime{}
  206. if bytes.Equal(b, jsonNull) {
  207. return nil
  208. }
  209. s, err := strconv.Unquote(string(b))
  210. if err != nil {
  211. return err
  212. }
  213. dt, err := parseCivilDateTime(s)
  214. if err != nil {
  215. return err
  216. }
  217. n.DateTime = dt
  218. n.Valid = true
  219. return nil
  220. }
  221. var (
  222. typeOfNullInt64 = reflect.TypeOf(NullInt64{})
  223. typeOfNullFloat64 = reflect.TypeOf(NullFloat64{})
  224. typeOfNullBool = reflect.TypeOf(NullBool{})
  225. typeOfNullString = reflect.TypeOf(NullString{})
  226. typeOfNullTimestamp = reflect.TypeOf(NullTimestamp{})
  227. typeOfNullDate = reflect.TypeOf(NullDate{})
  228. typeOfNullTime = reflect.TypeOf(NullTime{})
  229. typeOfNullDateTime = reflect.TypeOf(NullDateTime{})
  230. )
  231. func nullableFieldType(t reflect.Type) FieldType {
  232. switch t {
  233. case typeOfNullInt64:
  234. return IntegerFieldType
  235. case typeOfNullFloat64:
  236. return FloatFieldType
  237. case typeOfNullBool:
  238. return BooleanFieldType
  239. case typeOfNullString:
  240. return StringFieldType
  241. case typeOfNullTimestamp:
  242. return TimestampFieldType
  243. case typeOfNullDate:
  244. return DateFieldType
  245. case typeOfNullTime:
  246. return TimeFieldType
  247. case typeOfNullDateTime:
  248. return DateTimeFieldType
  249. default:
  250. return ""
  251. }
  252. }