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.
gojobs/vendor/github.com/upper/db/v4/adapter/postgresql/custom_types_pq.go

270 lines
7.1 KiB

// +build pq
package postgresql
// Copyright (c) 2012-present The upper.io/db authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import (
"bytes"
"database/sql/driver"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"time"
"github.com/lib/pq"
)
// JSONB represents a PostgreSQL's JSONB value:
// https://www.postgresql.org/docs/9.6/static/datatype-json.html. JSONB
// satisfies sqlbuilder.ScannerValuer.
type JSONB struct {
Data interface{}
}
// MarshalJSON encodes the wrapper value as JSON.
func (j JSONB) MarshalJSON() ([]byte, error) {
return json.Marshal(j.Data)
}
// UnmarshalJSON decodes the given JSON into the wrapped value.
func (j *JSONB) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
j.Data = v
return nil
}
// Scan satisfies the sql.Scanner interface.
func (j *JSONB) Scan(src interface{}) error {
if j.Data == nil {
return nil
}
if src == nil {
dv := reflect.Indirect(reflect.ValueOf(j.Data))
dv.Set(reflect.Zero(dv.Type()))
return nil
}
b, ok := src.([]byte)
if !ok {
return errors.New("Scan source was not []bytes")
}
if err := json.Unmarshal(b, j.Data); err != nil {
return err
}
return nil
}
// Value satisfies the driver.Valuer interface.
func (j JSONB) Value() (driver.Value, error) {
// See https://github.com/lib/pq/issues/528#issuecomment-257197239 on why are
// we returning string instead of []byte.
if j.Data == nil {
return nil, nil
}
if v, ok := j.Data.(json.RawMessage); ok {
return string(v), nil
}
b, err := json.Marshal(j.Data)
if err != nil {
return nil, err
}
return string(b), nil
}
// StringArray represents a one-dimensional array of strings (`[]string{}`)
// that is compatible with PostgreSQL's text array (`text[]`). StringArray
// satisfies sqlbuilder.ScannerValuer.
type StringArray pq.StringArray
// Value satisfies the driver.Valuer interface.
func (a StringArray) Value() (driver.Value, error) {
return pq.StringArray(a).Value()
}
// Scan satisfies the sql.Scanner interface.
func (a *StringArray) Scan(src interface{}) error {
s := pq.StringArray(*a)
if err := s.Scan(src); err != nil {
return err
}
*a = StringArray(s)
return nil
}
// Int64Array represents a one-dimensional array of int64s (`[]int64{}`) that
// is compatible with PostgreSQL's integer array (`integer[]`). Int64Array
// satisfies sqlbuilder.ScannerValuer.
type Int64Array pq.Int64Array
// Value satisfies the driver.Valuer interface.
func (i Int64Array) Value() (driver.Value, error) {
return pq.Int64Array(i).Value()
}
// Scan satisfies the sql.Scanner interface.
func (i *Int64Array) Scan(src interface{}) error {
s := pq.Int64Array(*i)
if err := s.Scan(src); err != nil {
return err
}
*i = Int64Array(s)
return nil
}
// Float64Array represents a one-dimensional array of float64s (`[]float64{}`)
// that is compatible with PostgreSQL's double precision array (`double
// precision[]`). Float64Array satisfies sqlbuilder.ScannerValuer.
type Float64Array pq.Float64Array
// Value satisfies the driver.Valuer interface.
func (f Float64Array) Value() (driver.Value, error) {
return pq.Float64Array(f).Value()
}
// Scan satisfies the sql.Scanner interface.
func (f *Float64Array) Scan(src interface{}) error {
s := pq.Float64Array(*f)
if err := s.Scan(src); err != nil {
return err
}
*f = Float64Array(s)
return nil
}
// Float32Array represents a one-dimensional array of float32s (`[]float32{}`)
// that is compatible with PostgreSQL's double precision array (`double
// precision[]`). Float32Array satisfies sqlbuilder.ScannerValuer.
type Float32Array pq.Float32Array
// Value satisfies the driver.Valuer interface.
func (f Float32Array) Value() (driver.Value, error) {
return pq.Float32Array(f).Value()
}
// Scan satisfies the sql.Scanner interface.
func (f *Float32Array) Scan(src interface{}) error {
s := pq.Float32Array(*f)
if err := s.Scan(src); err != nil {
return err
}
*f = Float32Array(s)
return nil
}
// BoolArray represents a one-dimensional array of int64s (`[]bool{}`) that
// is compatible with PostgreSQL's boolean type (`boolean[]`). BoolArray
// satisfies sqlbuilder.ScannerValuer.
type BoolArray pq.BoolArray
// Value satisfies the driver.Valuer interface.
func (b BoolArray) Value() (driver.Value, error) {
return pq.BoolArray(b).Value()
}
// Scan satisfies the sql.Scanner interface.
func (b *BoolArray) Scan(src interface{}) error {
s := pq.BoolArray(*b)
if err := s.Scan(src); err != nil {
return err
}
*b = BoolArray(s)
return nil
}
type Bytea []byte
// Scan satisfies the sql.Scanner interface.
func (b *Bytea) Scan(src interface{}) error {
decoded, err := parseBytea(src.([]byte))
if err != nil {
return err
}
if len(decoded) < 1 {
*b = nil
return nil
}
(*b) = make(Bytea, len(decoded))
for i := range decoded {
(*b)[i] = decoded[i]
}
return nil
}
type Time time.Time
// Parse a bytea value received from the server. Both "hex" and the legacy
// "escape" format are supported.
func parseBytea(s []byte) (result []byte, err error) {
if len(s) >= 2 && bytes.Equal(s[:2], []byte("\\x")) {
// bytea_output = hex
s = s[2:] // trim off leading "\\x"
result = make([]byte, hex.DecodedLen(len(s)))
_, err := hex.Decode(result, s)
if err != nil {
return nil, err
}
} else {
// bytea_output = escape
for len(s) > 0 {
if s[0] == '\\' {
// escaped '\\'
if len(s) >= 2 && s[1] == '\\' {
result = append(result, '\\')
s = s[2:]
continue
}
// '\\' followed by an octal number
if len(s) < 4 {
return nil, fmt.Errorf("invalid bytea sequence %v", s)
}
r, err := strconv.ParseInt(string(s[1:4]), 8, 9)
if err != nil {
return nil, fmt.Errorf("could not parse bytea value: %s", err.Error())
}
result = append(result, byte(r))
s = s[4:]
} else {
// We hit an unescaped, raw byte. Try to read in as many as
// possible in one go.
i := bytes.IndexByte(s, '\\')
if i == -1 {
result = append(result, s...)
break
}
result = append(result, s[:i]...)
s = s[i:]
}
}
}
return result, nil
}