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.
 
 
 

349 lines
8.2 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. // NullGeography represents a BigQuery GEOGRAPHY string that may be NULL.
  37. type NullGeography struct {
  38. GeographyVal string
  39. Valid bool // Valid is true if GeographyVal is not NULL.
  40. }
  41. func (n NullGeography) String() string { return nullstr(n.Valid, n.GeographyVal) }
  42. // NullFloat64 represents a BigQuery FLOAT64 that may be NULL.
  43. type NullFloat64 struct {
  44. Float64 float64
  45. Valid bool // Valid is true if Float64 is not NULL.
  46. }
  47. func (n NullFloat64) String() string { return nullstr(n.Valid, n.Float64) }
  48. // NullBool represents a BigQuery BOOL that may be NULL.
  49. type NullBool struct {
  50. Bool bool
  51. Valid bool // Valid is true if Bool is not NULL.
  52. }
  53. func (n NullBool) String() string { return nullstr(n.Valid, n.Bool) }
  54. // NullTimestamp represents a BigQuery TIMESTAMP that may be null.
  55. type NullTimestamp struct {
  56. Timestamp time.Time
  57. Valid bool // Valid is true if Time is not NULL.
  58. }
  59. func (n NullTimestamp) String() string { return nullstr(n.Valid, n.Timestamp) }
  60. // NullDate represents a BigQuery DATE that may be null.
  61. type NullDate struct {
  62. Date civil.Date
  63. Valid bool // Valid is true if Date is not NULL.
  64. }
  65. func (n NullDate) String() string { return nullstr(n.Valid, n.Date) }
  66. // NullTime represents a BigQuery TIME that may be null.
  67. type NullTime struct {
  68. Time civil.Time
  69. Valid bool // Valid is true if Time is not NULL.
  70. }
  71. func (n NullTime) String() string {
  72. if !n.Valid {
  73. return "<null>"
  74. }
  75. return CivilTimeString(n.Time)
  76. }
  77. // NullDateTime represents a BigQuery DATETIME that may be null.
  78. type NullDateTime struct {
  79. DateTime civil.DateTime
  80. Valid bool // Valid is true if DateTime is not NULL.
  81. }
  82. func (n NullDateTime) String() string {
  83. if !n.Valid {
  84. return "<null>"
  85. }
  86. return CivilDateTimeString(n.DateTime)
  87. }
  88. // MarshalJSON converts the NullInt64 to JSON.
  89. func (n NullInt64) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Int64) }
  90. // MarshalJSON converts the NullFloat64 to JSON.
  91. func (n NullFloat64) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Float64) }
  92. // MarshalJSON converts the NullBool to JSON.
  93. func (n NullBool) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Bool) }
  94. // MarshalJSON converts the NullString to JSON.
  95. func (n NullString) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.StringVal) }
  96. // MarshalJSON converts the NullGeography to JSON.
  97. func (n NullGeography) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.GeographyVal) }
  98. // MarshalJSON converts the NullTimestamp to JSON.
  99. func (n NullTimestamp) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Timestamp) }
  100. // MarshalJSON converts the NullDate to JSON.
  101. func (n NullDate) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Date) }
  102. // MarshalJSON converts the NullTime to JSON.
  103. func (n NullTime) MarshalJSON() ([]byte, error) {
  104. if !n.Valid {
  105. return jsonNull, nil
  106. }
  107. return []byte(`"` + CivilTimeString(n.Time) + `"`), nil
  108. }
  109. // MarshalJSON converts the NullDateTime to JSON.
  110. func (n NullDateTime) MarshalJSON() ([]byte, error) {
  111. if !n.Valid {
  112. return jsonNull, nil
  113. }
  114. return []byte(`"` + CivilDateTimeString(n.DateTime) + `"`), nil
  115. }
  116. func nullstr(valid bool, v interface{}) string {
  117. if !valid {
  118. return "NULL"
  119. }
  120. return fmt.Sprint(v)
  121. }
  122. var jsonNull = []byte("null")
  123. func nulljson(valid bool, v interface{}) ([]byte, error) {
  124. if !valid {
  125. return jsonNull, nil
  126. }
  127. return json.Marshal(v)
  128. }
  129. // UnmarshalJSON converts JSON into a NullInt64.
  130. func (n *NullInt64) UnmarshalJSON(b []byte) error {
  131. n.Valid = false
  132. n.Int64 = 0
  133. if bytes.Equal(b, jsonNull) {
  134. return nil
  135. }
  136. if err := json.Unmarshal(b, &n.Int64); err != nil {
  137. return err
  138. }
  139. n.Valid = true
  140. return nil
  141. }
  142. // UnmarshalJSON converts JSON into a NullFloat64.
  143. func (n *NullFloat64) UnmarshalJSON(b []byte) error {
  144. n.Valid = false
  145. n.Float64 = 0
  146. if bytes.Equal(b, jsonNull) {
  147. return nil
  148. }
  149. if err := json.Unmarshal(b, &n.Float64); err != nil {
  150. return err
  151. }
  152. n.Valid = true
  153. return nil
  154. }
  155. // UnmarshalJSON converts JSON into a NullBool.
  156. func (n *NullBool) UnmarshalJSON(b []byte) error {
  157. n.Valid = false
  158. n.Bool = false
  159. if bytes.Equal(b, jsonNull) {
  160. return nil
  161. }
  162. if err := json.Unmarshal(b, &n.Bool); err != nil {
  163. return err
  164. }
  165. n.Valid = true
  166. return nil
  167. }
  168. // UnmarshalJSON converts JSON into a NullString.
  169. func (n *NullString) UnmarshalJSON(b []byte) error {
  170. n.Valid = false
  171. n.StringVal = ""
  172. if bytes.Equal(b, jsonNull) {
  173. return nil
  174. }
  175. if err := json.Unmarshal(b, &n.StringVal); err != nil {
  176. return err
  177. }
  178. n.Valid = true
  179. return nil
  180. }
  181. // UnmarshalJSON converts JSON into a NullGeography.
  182. func (n *NullGeography) UnmarshalJSON(b []byte) error {
  183. n.Valid = false
  184. n.GeographyVal = ""
  185. if bytes.Equal(b, jsonNull) {
  186. return nil
  187. }
  188. if err := json.Unmarshal(b, &n.GeographyVal); err != nil {
  189. return err
  190. }
  191. n.Valid = true
  192. return nil
  193. }
  194. // UnmarshalJSON converts JSON into a NullTimestamp.
  195. func (n *NullTimestamp) UnmarshalJSON(b []byte) error {
  196. n.Valid = false
  197. n.Timestamp = time.Time{}
  198. if bytes.Equal(b, jsonNull) {
  199. return nil
  200. }
  201. if err := json.Unmarshal(b, &n.Timestamp); err != nil {
  202. return err
  203. }
  204. n.Valid = true
  205. return nil
  206. }
  207. // UnmarshalJSON converts JSON into a NullDate.
  208. func (n *NullDate) UnmarshalJSON(b []byte) error {
  209. n.Valid = false
  210. n.Date = civil.Date{}
  211. if bytes.Equal(b, jsonNull) {
  212. return nil
  213. }
  214. if err := json.Unmarshal(b, &n.Date); err != nil {
  215. return err
  216. }
  217. n.Valid = true
  218. return nil
  219. }
  220. // UnmarshalJSON converts JSON into a NullTime.
  221. func (n *NullTime) UnmarshalJSON(b []byte) error {
  222. n.Valid = false
  223. n.Time = civil.Time{}
  224. if bytes.Equal(b, jsonNull) {
  225. return nil
  226. }
  227. s, err := strconv.Unquote(string(b))
  228. if err != nil {
  229. return err
  230. }
  231. t, err := civil.ParseTime(s)
  232. if err != nil {
  233. return err
  234. }
  235. n.Time = t
  236. n.Valid = true
  237. return nil
  238. }
  239. // UnmarshalJSON converts JSON into a NullDateTime.
  240. func (n *NullDateTime) UnmarshalJSON(b []byte) error {
  241. n.Valid = false
  242. n.DateTime = civil.DateTime{}
  243. if bytes.Equal(b, jsonNull) {
  244. return nil
  245. }
  246. s, err := strconv.Unquote(string(b))
  247. if err != nil {
  248. return err
  249. }
  250. dt, err := parseCivilDateTime(s)
  251. if err != nil {
  252. return err
  253. }
  254. n.DateTime = dt
  255. n.Valid = true
  256. return nil
  257. }
  258. var (
  259. typeOfNullInt64 = reflect.TypeOf(NullInt64{})
  260. typeOfNullFloat64 = reflect.TypeOf(NullFloat64{})
  261. typeOfNullBool = reflect.TypeOf(NullBool{})
  262. typeOfNullString = reflect.TypeOf(NullString{})
  263. typeOfNullGeography = reflect.TypeOf(NullGeography{})
  264. typeOfNullTimestamp = reflect.TypeOf(NullTimestamp{})
  265. typeOfNullDate = reflect.TypeOf(NullDate{})
  266. typeOfNullTime = reflect.TypeOf(NullTime{})
  267. typeOfNullDateTime = reflect.TypeOf(NullDateTime{})
  268. )
  269. func nullableFieldType(t reflect.Type) FieldType {
  270. switch t {
  271. case typeOfNullInt64:
  272. return IntegerFieldType
  273. case typeOfNullFloat64:
  274. return FloatFieldType
  275. case typeOfNullBool:
  276. return BooleanFieldType
  277. case typeOfNullString:
  278. return StringFieldType
  279. case typeOfNullGeography:
  280. return GeographyFieldType
  281. case typeOfNullTimestamp:
  282. return TimestampFieldType
  283. case typeOfNullDate:
  284. return DateFieldType
  285. case typeOfNullTime:
  286. return TimeFieldType
  287. case typeOfNullDateTime:
  288. return DateTimeFieldType
  289. default:
  290. return ""
  291. }
  292. }