Skip to content

Commit

Permalink
db/lib/sqlbuilder: add missing custom_types.go file
Browse files Browse the repository at this point in the history
  • Loading branch information
xiam committed Aug 19, 2017
1 parent 92c8aa9 commit ed47f42
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 21 deletions.
61 changes: 61 additions & 0 deletions lib/sqlbuilder/custom_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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.

package sqlbuilder

import (
"database/sql"
"database/sql/driver"

"reflect"
)

var (
// ValuerType is the reflection type for the driver.Valuer interface.
ValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()

// ScannerType is the reflection type for the sql.Scanner interface.
ScannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem()

// ValueWrapperType is the reflection type for the sql.ValueWrapper interface.
ValueWrapperType = reflect.TypeOf((*ValueWrapper)(nil)).Elem()
)

// ValueWrapper defines a method WrapValue that query arguments can use to wrap
// themselves around helper types right before being used in a query.
//
// Example:
//
// func (a MyCustomArray) WrapValue(value interface{}) interface{} {
// // postgresql.Array adds a driver.Valuer and sql.Scanner around
// // custom arrays.
// return postgresql.Array(values)
// }
type ValueWrapper interface {
WrapValue(value interface{}) interface{}
}

// ScannerValuer represents a value that satisfies both driver.Valuer and
// sql.Scanner interfaces.
type ScannerValuer interface {
driver.Valuer
sql.Scanner
}
12 changes: 6 additions & 6 deletions postgresql/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,11 @@ type customJSONB struct {
}

func (c customJSONB) Value() (driver.Value, error) {
return ToJSONBValue(c)
return JSONBValue(c)
}

func (c *customJSONB) Scan(src interface{}) error {
return FromJSONBValue(c, src)
return ScanJSONB(c, src)
}

type autoCustomJSONB struct {
Expand Down Expand Up @@ -332,8 +332,8 @@ func testPostgreSQLTypes(t *testing.T, sess sqlbuilder.Database) {
Int64Value int64Compat `db:"int64_value"`
Int64ValueArray int64CompatArray `db:"int64_value_array"`

IntegerArray Int64Array `db:"integer_array"`
StringArray StringArray `db:"string_array"`
IntegerArray Int64Array `db:"integer_array,jsonb"`
StringArray StringArray `db:"string_array,stringarray"`
JSONBMap JSONBMap `db:"jsonb_map"`

PGTypeInline `db:",inline"`
Expand Down Expand Up @@ -836,10 +836,10 @@ type Settings struct {
}

func (s *Settings) Scan(src interface{}) error {
return FromJSONBValue(s, src)
return ScanJSONB(s, src)
}
func (s Settings) Value() (driver.Value, error) {
return ToJSONBValue(s)
return JSONBValue(s)
}

func TestOptionTypeJsonbStruct(t *testing.T) {
Expand Down
26 changes: 18 additions & 8 deletions postgresql/custom_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,13 @@ type JSONBMap map[string]interface{}

// Value satisfies the driver.Valuer interface.
func (m JSONBMap) Value() (driver.Value, error) {
return ToJSONBValue(m)
return JSONBValue(m)
}

// Scan satisfies the sql.Scanner interface.
func (m *JSONBMap) Scan(src interface{}) error {
*m = map[string]interface{}(nil)
return FromJSONBValue(m, src)
return ScanJSONB(m, src)
}

// JSONBArray represents an array of any type (`[]interface{}`) that is
Expand All @@ -218,27 +218,37 @@ type JSONBArray []interface{}

// Value satisfies the driver.Valuer interface.
func (a JSONBArray) Value() (driver.Value, error) {
return ToJSONBValue(a)
return JSONBValue(a)
}

// Scan satisfies the sql.Scanner interface.
func (a *JSONBArray) Scan(src interface{}) error {
return FromJSONBValue(a, src)
return ScanJSONB(a, src)
}

// ToJSONBValue takes an interface and provides a driver.Value that can be
// JSONBValue takes an interface and provides a driver.Value that can be
// stored as a JSONB column.
func ToJSONBValue(i interface{}) (driver.Value, error) {
func JSONBValue(i interface{}) (driver.Value, error) {
v := JSONB{i}
return v.Value()
}

// FromJSONBValue decodes a JSON byte stream into the passed dst value.
func FromJSONBValue(dst interface{}, src interface{}) error {
// ScanJSONB decodes a JSON byte stream into the passed dst value.
func ScanJSONB(dst interface{}, src interface{}) error {
v := JSONB{dst}
return v.Scan(src)
}

// EncodeJSONB is deprecated and going to be removed. Use ScanJSONB instead.
func EncodeJSONB(i interface{}) (driver.Value, error) {
return JSONBValue(i)
}

// DecodeJSONB is deprecated and going to be removed. Use JSONBValue instead.
func DecodeJSONB(dst interface{}, src interface{}) error {
return ScanJSONB(dst, src)
}

// JSONBConverter provides a helper method WrapValue that satisfies
// sqlbuilder.ValueWrapper, can be used to encode Go structs into JSONB
// PostgreSQL types and vice versa.
Expand Down
14 changes: 7 additions & 7 deletions postgresql/custom_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,46 @@ type testStruct struct {
V JSONB `json:"v"`
}

func TestFromJSONBValue(t *testing.T) {
func TestScanJSONB(t *testing.T) {
{
a := testStruct{}
err := FromJSONBValue(&a, []byte(`{"x": 5, "z": "Hello", "v": 1}`))
err := ScanJSONB(&a, []byte(`{"x": 5, "z": "Hello", "v": 1}`))
assert.NoError(t, err)
assert.Equal(t, "Hello", a.Z)
assert.Equal(t, float64(1), a.V.V)
assert.Equal(t, 5, a.X)
}
{
a := testStruct{}
err := FromJSONBValue(&a, []byte(`{"x": 5, "z": "Hello", "v": null}`))
err := DecodeJSONB(&a, []byte(`{"x": 5, "z": "Hello", "v": null}`))
assert.NoError(t, err)
assert.Equal(t, "Hello", a.Z)
assert.Equal(t, nil, a.V.V)
assert.Equal(t, 5, a.X)
}
{
a := testStruct{}
err := FromJSONBValue(&a, []byte(`{"x": 5, "z": "Hello"}`))
err := ScanJSONB(&a, []byte(`{"x": 5, "z": "Hello"}`))
assert.NoError(t, err)
assert.Equal(t, "Hello", a.Z)
assert.Equal(t, nil, a.V.V)
assert.Equal(t, 5, a.X)
}
{
a := testStruct{}
err := FromJSONBValue(&a, []byte(`{"v": "Hello"}`))
err := ScanJSONB(&a, []byte(`{"v": "Hello"}`))
assert.NoError(t, err)
assert.Equal(t, "Hello", a.V.V)
}
{
a := testStruct{}
err := FromJSONBValue(&a, []byte(`{"v": true}`))
err := ScanJSONB(&a, []byte(`{"v": true}`))
assert.NoError(t, err)
assert.Equal(t, true, a.V.V)
}
{
a := testStruct{}
err := FromJSONBValue(&a, []byte(`{}`))
err := ScanJSONB(&a, []byte(`{}`))
assert.NoError(t, err)
assert.Equal(t, nil, a.V.V)
}
Expand Down

0 comments on commit ed47f42

Please sign in to comment.