...

Source file src/cloud.google.com/go/bigquery/nulls.go

Documentation: cloud.google.com/go/bigquery

     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  
    15  package bigquery
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/json"
    20  	"fmt"
    21  	"math"
    22  	"reflect"
    23  	"strconv"
    24  	"time"
    25  
    26  	"cloud.google.com/go/civil"
    27  )
    28  
    29  var (
    30  	jsonNull      = []byte("null")
    31  	posInf        = []byte(`"+Inf"`)
    32  	inf           = []byte(`"Inf"`)
    33  	minusInf      = []byte(`"-Inf"`)
    34  	infinity      = []byte(`"Infinity"`)
    35  	minusInfinity = []byte(`"-Infinity"`)
    36  	nan           = []byte(`"NaN"`)
    37  )
    38  
    39  // NullInt64 represents a BigQuery INT64 that may be NULL.
    40  type NullInt64 struct {
    41  	Int64 int64
    42  	Valid bool // Valid is true if Int64 is not NULL.
    43  }
    44  
    45  func (n NullInt64) String() string { return nullstr(n.Valid, n.Int64) }
    46  
    47  // NullString represents a BigQuery STRING that may be NULL.
    48  type NullString struct {
    49  	StringVal string
    50  	Valid     bool // Valid is true if StringVal is not NULL.
    51  }
    52  
    53  func (n NullString) String() string { return nullstr(n.Valid, n.StringVal) }
    54  
    55  // NullGeography represents a BigQuery GEOGRAPHY string that may be NULL.
    56  type NullGeography struct {
    57  	GeographyVal string
    58  	Valid        bool // Valid is true if GeographyVal is not NULL.
    59  }
    60  
    61  func (n NullGeography) String() string { return nullstr(n.Valid, n.GeographyVal) }
    62  
    63  // NullJSON represents a BigQuery JSON string that may be NULL.
    64  type NullJSON struct {
    65  	JSONVal string
    66  	Valid   bool // Valid is true if JSONVal is not NULL.
    67  }
    68  
    69  func (n NullJSON) String() string { return nullstr(n.Valid, n.JSONVal) }
    70  
    71  // NullFloat64 represents a BigQuery FLOAT64 that may be NULL.
    72  type NullFloat64 struct {
    73  	Float64 float64
    74  	Valid   bool // Valid is true if Float64 is not NULL.
    75  }
    76  
    77  func (n NullFloat64) String() string { return nullstr(n.Valid, n.Float64) }
    78  
    79  // NullBool represents a BigQuery BOOL that may be NULL.
    80  type NullBool struct {
    81  	Bool  bool
    82  	Valid bool // Valid is true if Bool is not NULL.
    83  }
    84  
    85  func (n NullBool) String() string { return nullstr(n.Valid, n.Bool) }
    86  
    87  // NullTimestamp represents a BigQuery TIMESTAMP that may be null.
    88  type NullTimestamp struct {
    89  	Timestamp time.Time
    90  	Valid     bool // Valid is true if Time is not NULL.
    91  }
    92  
    93  func (n NullTimestamp) String() string { return nullstr(n.Valid, n.Timestamp) }
    94  
    95  // NullDate represents a BigQuery DATE that may be null.
    96  type NullDate struct {
    97  	Date  civil.Date
    98  	Valid bool // Valid is true if Date is not NULL.
    99  }
   100  
   101  func (n NullDate) String() string { return nullstr(n.Valid, n.Date) }
   102  
   103  // NullTime represents a BigQuery TIME that may be null.
   104  type NullTime struct {
   105  	Time  civil.Time
   106  	Valid bool // Valid is true if Time is not NULL.
   107  }
   108  
   109  func (n NullTime) String() string {
   110  	if !n.Valid {
   111  		return "<null>"
   112  	}
   113  	return CivilTimeString(n.Time)
   114  }
   115  
   116  // NullDateTime represents a BigQuery DATETIME that may be null.
   117  type NullDateTime struct {
   118  	DateTime civil.DateTime
   119  	Valid    bool // Valid is true if DateTime is not NULL.
   120  }
   121  
   122  func (n NullDateTime) String() string {
   123  	if !n.Valid {
   124  		return "<null>"
   125  	}
   126  	return CivilDateTimeString(n.DateTime)
   127  }
   128  
   129  // MarshalJSON converts the NullInt64 to JSON.
   130  func (n NullInt64) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Int64) }
   131  
   132  // MarshalJSON converts the NullFloat64 to JSON.
   133  func (n NullFloat64) MarshalJSON() (b []byte, err error) {
   134  	if n.Valid {
   135  		switch {
   136  		case math.IsInf(n.Float64, 1):
   137  			return infinity, nil
   138  		case math.IsInf(n.Float64, -1):
   139  			return minusInfinity, nil
   140  		case math.IsNaN(n.Float64):
   141  			return nan, nil
   142  		default:
   143  			return json.Marshal(n.Float64)
   144  		}
   145  	}
   146  	return jsonNull, nil
   147  }
   148  
   149  // MarshalJSON converts the NullBool to JSON.
   150  func (n NullBool) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Bool) }
   151  
   152  // MarshalJSON converts the NullString to JSON.
   153  func (n NullString) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.StringVal) }
   154  
   155  // MarshalJSON converts the NullGeography to JSON.
   156  func (n NullGeography) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.GeographyVal) }
   157  
   158  // MarshalJSON converts the NullJSON to JSON.
   159  func (n NullJSON) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.JSONVal) }
   160  
   161  // MarshalJSON converts the NullTimestamp to JSON.
   162  func (n NullTimestamp) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Timestamp) }
   163  
   164  // MarshalJSON converts the NullDate to JSON.
   165  func (n NullDate) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Date) }
   166  
   167  // MarshalJSON converts the NullTime to JSON.
   168  func (n NullTime) MarshalJSON() ([]byte, error) {
   169  	if !n.Valid {
   170  		return jsonNull, nil
   171  	}
   172  	return []byte(`"` + CivilTimeString(n.Time) + `"`), nil
   173  }
   174  
   175  // MarshalJSON converts the NullDateTime to JSON.
   176  func (n NullDateTime) MarshalJSON() ([]byte, error) {
   177  	if !n.Valid {
   178  		return jsonNull, nil
   179  	}
   180  	return []byte(`"` + CivilDateTimeString(n.DateTime) + `"`), nil
   181  }
   182  
   183  func nullstr(valid bool, v interface{}) string {
   184  	if !valid {
   185  		return "NULL"
   186  	}
   187  	return fmt.Sprint(v)
   188  }
   189  
   190  func nulljson(valid bool, v interface{}) ([]byte, error) {
   191  	if !valid {
   192  		return jsonNull, nil
   193  	}
   194  	return json.Marshal(v)
   195  }
   196  
   197  // UnmarshalJSON converts JSON into a NullInt64.
   198  func (n *NullInt64) UnmarshalJSON(b []byte) error {
   199  	n.Valid = false
   200  	n.Int64 = 0
   201  	if bytes.Equal(b, jsonNull) {
   202  		return nil
   203  	}
   204  
   205  	if err := json.Unmarshal(b, &n.Int64); err != nil {
   206  		return err
   207  	}
   208  	n.Valid = true
   209  	return nil
   210  }
   211  
   212  // UnmarshalJSON converts JSON into a NullFloat64.
   213  func (n *NullFloat64) UnmarshalJSON(b []byte) error {
   214  	n.Valid = false
   215  	n.Float64 = 0
   216  	if bytes.Equal(b, jsonNull) {
   217  		return nil
   218  	} else if bytes.Equal(b, posInf) || bytes.Equal(b, inf) || bytes.Equal(b, infinity) {
   219  		n.Float64 = math.Inf(1)
   220  		n.Valid = true
   221  		return nil
   222  	} else if bytes.Equal(b, minusInf) || bytes.Equal(b, minusInfinity) {
   223  		n.Float64 = math.Inf(-1)
   224  		n.Valid = true
   225  		return nil
   226  	} else if bytes.Equal(b, nan) {
   227  		n.Float64 = math.NaN()
   228  		n.Valid = true
   229  		return nil
   230  	}
   231  	if err := json.Unmarshal(b, &n.Float64); err != nil {
   232  		return err
   233  	}
   234  	n.Valid = true
   235  	return nil
   236  }
   237  
   238  // UnmarshalJSON converts JSON into a NullBool.
   239  func (n *NullBool) UnmarshalJSON(b []byte) error {
   240  	n.Valid = false
   241  	n.Bool = false
   242  	if bytes.Equal(b, jsonNull) {
   243  		return nil
   244  	}
   245  
   246  	if err := json.Unmarshal(b, &n.Bool); err != nil {
   247  		return err
   248  	}
   249  	n.Valid = true
   250  	return nil
   251  }
   252  
   253  // UnmarshalJSON converts JSON into a NullString.
   254  func (n *NullString) UnmarshalJSON(b []byte) error {
   255  	n.Valid = false
   256  	n.StringVal = ""
   257  	if bytes.Equal(b, jsonNull) {
   258  		return nil
   259  	}
   260  
   261  	if err := json.Unmarshal(b, &n.StringVal); err != nil {
   262  		return err
   263  	}
   264  	n.Valid = true
   265  	return nil
   266  }
   267  
   268  // UnmarshalJSON converts JSON into a NullGeography.
   269  func (n *NullGeography) UnmarshalJSON(b []byte) error {
   270  	n.Valid = false
   271  	n.GeographyVal = ""
   272  	if bytes.Equal(b, jsonNull) {
   273  		return nil
   274  	}
   275  	if err := json.Unmarshal(b, &n.GeographyVal); err != nil {
   276  		return err
   277  	}
   278  	n.Valid = true
   279  	return nil
   280  }
   281  
   282  // UnmarshalJSON converts JSON into a NullJSON.
   283  func (n *NullJSON) UnmarshalJSON(b []byte) error {
   284  	n.Valid = false
   285  	n.JSONVal = ""
   286  	if bytes.Equal(b, jsonNull) {
   287  		return nil
   288  	}
   289  	if err := json.Unmarshal(b, &n.JSONVal); err != nil {
   290  		return err
   291  	}
   292  	n.Valid = true
   293  	return nil
   294  }
   295  
   296  // UnmarshalJSON converts JSON into a NullTimestamp.
   297  func (n *NullTimestamp) UnmarshalJSON(b []byte) error {
   298  	n.Valid = false
   299  	n.Timestamp = time.Time{}
   300  	if bytes.Equal(b, jsonNull) {
   301  		return nil
   302  	}
   303  
   304  	if err := json.Unmarshal(b, &n.Timestamp); err != nil {
   305  		return err
   306  	}
   307  	n.Valid = true
   308  	return nil
   309  }
   310  
   311  // UnmarshalJSON converts JSON into a NullDate.
   312  func (n *NullDate) UnmarshalJSON(b []byte) error {
   313  	n.Valid = false
   314  	n.Date = civil.Date{}
   315  	if bytes.Equal(b, jsonNull) {
   316  		return nil
   317  	}
   318  
   319  	if err := json.Unmarshal(b, &n.Date); err != nil {
   320  		return err
   321  	}
   322  	n.Valid = true
   323  	return nil
   324  }
   325  
   326  // UnmarshalJSON converts JSON into a NullTime.
   327  func (n *NullTime) UnmarshalJSON(b []byte) error {
   328  	n.Valid = false
   329  	n.Time = civil.Time{}
   330  	if bytes.Equal(b, jsonNull) {
   331  		return nil
   332  	}
   333  
   334  	s, err := strconv.Unquote(string(b))
   335  	if err != nil {
   336  		return err
   337  	}
   338  
   339  	t, err := civil.ParseTime(s)
   340  	if err != nil {
   341  		return err
   342  	}
   343  	n.Time = t
   344  
   345  	n.Valid = true
   346  	return nil
   347  }
   348  
   349  // UnmarshalJSON converts JSON into a NullDateTime.
   350  func (n *NullDateTime) UnmarshalJSON(b []byte) error {
   351  	n.Valid = false
   352  	n.DateTime = civil.DateTime{}
   353  	if bytes.Equal(b, jsonNull) {
   354  		return nil
   355  	}
   356  
   357  	s, err := strconv.Unquote(string(b))
   358  	if err != nil {
   359  		return err
   360  	}
   361  
   362  	dt, err := parseCivilDateTime(s)
   363  	if err != nil {
   364  		return err
   365  	}
   366  	n.DateTime = dt
   367  
   368  	n.Valid = true
   369  	return nil
   370  }
   371  
   372  var (
   373  	typeOfNullInt64     = reflect.TypeOf(NullInt64{})
   374  	typeOfNullFloat64   = reflect.TypeOf(NullFloat64{})
   375  	typeOfNullBool      = reflect.TypeOf(NullBool{})
   376  	typeOfNullString    = reflect.TypeOf(NullString{})
   377  	typeOfNullGeography = reflect.TypeOf(NullGeography{})
   378  	typeOfNullJSON      = reflect.TypeOf(NullJSON{})
   379  	typeOfNullTimestamp = reflect.TypeOf(NullTimestamp{})
   380  	typeOfNullDate      = reflect.TypeOf(NullDate{})
   381  	typeOfNullTime      = reflect.TypeOf(NullTime{})
   382  	typeOfNullDateTime  = reflect.TypeOf(NullDateTime{})
   383  )
   384  
   385  func nullableFieldType(t reflect.Type) FieldType {
   386  	switch t {
   387  	case typeOfNullInt64:
   388  		return IntegerFieldType
   389  	case typeOfNullFloat64:
   390  		return FloatFieldType
   391  	case typeOfNullBool:
   392  		return BooleanFieldType
   393  	case typeOfNullString:
   394  		return StringFieldType
   395  	case typeOfNullGeography:
   396  		return GeographyFieldType
   397  	case typeOfNullJSON:
   398  		return JSONFieldType
   399  	case typeOfNullTimestamp:
   400  		return TimestampFieldType
   401  	case typeOfNullDate:
   402  		return DateFieldType
   403  	case typeOfNullTime:
   404  		return TimeFieldType
   405  	case typeOfNullDateTime:
   406  		return DateTimeFieldType
   407  	default:
   408  		return ""
   409  	}
   410  }
   411  

View as plain text