...

Source file src/github.com/jackc/pgtype/json.go

Documentation: github.com/jackc/pgtype

     1  package pgtype
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"reflect"
     9  )
    10  
    11  type JSON struct {
    12  	Bytes  []byte
    13  	Status Status
    14  }
    15  
    16  func (dst *JSON) Set(src interface{}) error {
    17  	if src == nil {
    18  		*dst = JSON{Status: Null}
    19  		return nil
    20  	}
    21  
    22  	if value, ok := src.(interface{ Get() interface{} }); ok {
    23  		value2 := value.Get()
    24  		if value2 != value {
    25  			return dst.Set(value2)
    26  		}
    27  	}
    28  
    29  	switch value := src.(type) {
    30  	case string:
    31  		*dst = JSON{Bytes: []byte(value), Status: Present}
    32  	case *string:
    33  		if value == nil {
    34  			*dst = JSON{Status: Null}
    35  		} else {
    36  			*dst = JSON{Bytes: []byte(*value), Status: Present}
    37  		}
    38  	case []byte:
    39  		if value == nil {
    40  			*dst = JSON{Status: Null}
    41  		} else {
    42  			*dst = JSON{Bytes: value, Status: Present}
    43  		}
    44  	// Encode* methods are defined on *JSON. If JSON is passed directly then the
    45  	// struct itself would be encoded instead of Bytes. This is clearly a footgun
    46  	// so detect and return an error. See https://github.com/jackc/pgx/issues/350.
    47  	case JSON:
    48  		return errors.New("use pointer to pgtype.JSON instead of value")
    49  	// Same as above but for JSONB (because they share implementation)
    50  	case JSONB:
    51  		return errors.New("use pointer to pgtype.JSONB instead of value")
    52  
    53  	default:
    54  		buf, err := json.Marshal(value)
    55  		if err != nil {
    56  			return err
    57  		}
    58  		*dst = JSON{Bytes: buf, Status: Present}
    59  	}
    60  
    61  	return nil
    62  }
    63  
    64  func (dst JSON) Get() interface{} {
    65  	switch dst.Status {
    66  	case Present:
    67  		var i interface{}
    68  		err := json.Unmarshal(dst.Bytes, &i)
    69  		if err != nil {
    70  			return dst
    71  		}
    72  		return i
    73  	case Null:
    74  		return nil
    75  	default:
    76  		return dst.Status
    77  	}
    78  }
    79  
    80  func (src *JSON) AssignTo(dst interface{}) error {
    81  	switch v := dst.(type) {
    82  	case *string:
    83  		if src.Status == Present {
    84  			*v = string(src.Bytes)
    85  		} else {
    86  			return fmt.Errorf("cannot assign non-present status to %T", dst)
    87  		}
    88  	case **string:
    89  		if src.Status == Present {
    90  			s := string(src.Bytes)
    91  			*v = &s
    92  			return nil
    93  		} else {
    94  			*v = nil
    95  			return nil
    96  		}
    97  	case *[]byte:
    98  		if src.Status != Present {
    99  			*v = nil
   100  		} else {
   101  			buf := make([]byte, len(src.Bytes))
   102  			copy(buf, src.Bytes)
   103  			*v = buf
   104  		}
   105  	default:
   106  		data := src.Bytes
   107  		if data == nil || src.Status != Present {
   108  			data = []byte("null")
   109  		}
   110  
   111  		p := reflect.ValueOf(dst).Elem()
   112  		p.Set(reflect.Zero(p.Type()))
   113  
   114  		return json.Unmarshal(data, dst)
   115  	}
   116  
   117  	return nil
   118  }
   119  
   120  func (JSON) PreferredResultFormat() int16 {
   121  	return TextFormatCode
   122  }
   123  
   124  func (dst *JSON) DecodeText(ci *ConnInfo, src []byte) error {
   125  	if src == nil {
   126  		*dst = JSON{Status: Null}
   127  		return nil
   128  	}
   129  
   130  	*dst = JSON{Bytes: src, Status: Present}
   131  	return nil
   132  }
   133  
   134  func (dst *JSON) DecodeBinary(ci *ConnInfo, src []byte) error {
   135  	return dst.DecodeText(ci, src)
   136  }
   137  
   138  func (JSON) PreferredParamFormat() int16 {
   139  	return TextFormatCode
   140  }
   141  
   142  func (src JSON) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
   143  	switch src.Status {
   144  	case Null:
   145  		return nil, nil
   146  	case Undefined:
   147  		return nil, errUndefined
   148  	}
   149  
   150  	return append(buf, src.Bytes...), nil
   151  }
   152  
   153  func (src JSON) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
   154  	return src.EncodeText(ci, buf)
   155  }
   156  
   157  // Scan implements the database/sql Scanner interface.
   158  func (dst *JSON) Scan(src interface{}) error {
   159  	if src == nil {
   160  		*dst = JSON{Status: Null}
   161  		return nil
   162  	}
   163  
   164  	switch src := src.(type) {
   165  	case string:
   166  		return dst.DecodeText(nil, []byte(src))
   167  	case []byte:
   168  		srcCopy := make([]byte, len(src))
   169  		copy(srcCopy, src)
   170  		return dst.DecodeText(nil, srcCopy)
   171  	}
   172  
   173  	return fmt.Errorf("cannot scan %T", src)
   174  }
   175  
   176  // Value implements the database/sql/driver Valuer interface.
   177  func (src JSON) Value() (driver.Value, error) {
   178  	switch src.Status {
   179  	case Present:
   180  		return src.Bytes, nil
   181  	case Null:
   182  		return nil, nil
   183  	default:
   184  		return nil, errUndefined
   185  	}
   186  }
   187  
   188  func (src JSON) MarshalJSON() ([]byte, error) {
   189  	switch src.Status {
   190  	case Present:
   191  		return src.Bytes, nil
   192  	case Null:
   193  		return []byte("null"), nil
   194  	case Undefined:
   195  		return nil, errUndefined
   196  	}
   197  
   198  	return nil, errBadStatus
   199  }
   200  
   201  func (dst *JSON) UnmarshalJSON(b []byte) error {
   202  	if b == nil || string(b) == "null" {
   203  		*dst = JSON{Status: Null}
   204  	} else {
   205  		*dst = JSON{Bytes: b, Status: Present}
   206  	}
   207  	return nil
   208  
   209  }
   210  

View as plain text