mirror of https://github.com/jackc/pgx.git
Add zeronull package for easier NULL <-> zero conversion
parent
186f4b3539
commit
0bbaad1348
|
@ -284,3 +284,153 @@ func TestDatabaseSQLSuccessfulNormalizeEqFunc(t testing.TB, driverName string, t
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoZeroToNullConversion(t testing.TB, pgTypeName string, zero interface{}) {
|
||||
TestPgxGoZeroToNullConversion(t, pgTypeName, zero)
|
||||
for _, driverName := range []string{"github.com/lib/pq", "github.com/jackc/pgx/stdlib"} {
|
||||
TestDatabaseSQLGoZeroToNullConversion(t, driverName, pgTypeName, zero)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNullToGoZeroConversion(t testing.TB, pgTypeName string, zero interface{}) {
|
||||
TestPgxNullToGoZeroConversion(t, pgTypeName, zero)
|
||||
for _, driverName := range []string{"github.com/lib/pq", "github.com/jackc/pgx/stdlib"} {
|
||||
TestDatabaseSQLNullToGoZeroConversion(t, driverName, pgTypeName, zero)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPgxGoZeroToNullConversion(t testing.TB, pgTypeName string, zero interface{}) {
|
||||
conn := MustConnectPgx(t)
|
||||
defer MustCloseContext(t, conn)
|
||||
|
||||
_, err := conn.Prepare(context.Background(), "test", fmt.Sprintf("select $1::%s is null", pgTypeName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
formats := []struct {
|
||||
name string
|
||||
formatCode int16
|
||||
}{
|
||||
{name: "TextFormat", formatCode: pgx.TextFormatCode},
|
||||
{name: "BinaryFormat", formatCode: pgx.BinaryFormatCode},
|
||||
}
|
||||
|
||||
for _, paramFormat := range formats {
|
||||
vEncoder := ForceEncoder(zero, paramFormat.formatCode)
|
||||
if vEncoder == nil {
|
||||
t.Logf("Skipping Param %s: %#v does not implement %v for encoding", paramFormat.name, zero, paramFormat.name)
|
||||
continue
|
||||
}
|
||||
|
||||
var result bool
|
||||
err := conn.QueryRow(context.Background(), "test", vEncoder).Scan(&result)
|
||||
if err != nil {
|
||||
t.Errorf("Param %s: %v", paramFormat.name, err)
|
||||
}
|
||||
|
||||
if !result {
|
||||
t.Errorf("Param %s: did not convert zero to null", paramFormat.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPgxNullToGoZeroConversion(t testing.TB, pgTypeName string, zero interface{}) {
|
||||
conn := MustConnectPgx(t)
|
||||
defer MustCloseContext(t, conn)
|
||||
|
||||
_, err := conn.Prepare(context.Background(), "test", fmt.Sprintf("select null::%s", pgTypeName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
formats := []struct {
|
||||
name string
|
||||
formatCode int16
|
||||
}{
|
||||
{name: "TextFormat", formatCode: pgx.TextFormatCode},
|
||||
{name: "BinaryFormat", formatCode: pgx.BinaryFormatCode},
|
||||
}
|
||||
|
||||
for _, resultFormat := range formats {
|
||||
|
||||
switch resultFormat.formatCode {
|
||||
case pgx.TextFormatCode:
|
||||
if _, ok := zero.(pgtype.TextEncoder); !ok {
|
||||
t.Logf("Skipping Result %s: %#v does not implement %v for decoding", resultFormat.name, zero, resultFormat.name)
|
||||
continue
|
||||
}
|
||||
case pgx.BinaryFormatCode:
|
||||
if _, ok := zero.(pgtype.BinaryEncoder); !ok {
|
||||
t.Logf("Skipping Result %s: %#v does not implement %v for decoding", resultFormat.name, zero, resultFormat.name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Derefence value if it is a pointer
|
||||
derefZero := zero
|
||||
refVal := reflect.ValueOf(zero)
|
||||
if refVal.Kind() == reflect.Ptr {
|
||||
derefZero = refVal.Elem().Interface()
|
||||
}
|
||||
|
||||
result := reflect.New(reflect.TypeOf(derefZero))
|
||||
|
||||
err := conn.QueryRow(context.Background(), "test").Scan(result.Interface())
|
||||
if err != nil {
|
||||
t.Errorf("Result %s: %v", resultFormat.name, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(result.Elem().Interface(), derefZero) {
|
||||
t.Errorf("Result %s: did not convert null to zero", resultFormat.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabaseSQLGoZeroToNullConversion(t testing.TB, driverName, pgTypeName string, zero interface{}) {
|
||||
conn := MustConnectDatabaseSQL(t, driverName)
|
||||
defer MustClose(t, conn)
|
||||
|
||||
ps, err := conn.Prepare(fmt.Sprintf("select $1::%s is null", pgTypeName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var result bool
|
||||
err = ps.QueryRow(zero).Scan(&result)
|
||||
if err != nil {
|
||||
t.Errorf("%v %v", driverName, err)
|
||||
}
|
||||
|
||||
if !result {
|
||||
t.Errorf("%v: did not convert zero to null", driverName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabaseSQLNullToGoZeroConversion(t testing.TB, driverName, pgTypeName string, zero interface{}) {
|
||||
conn := MustConnectDatabaseSQL(t, driverName)
|
||||
defer MustClose(t, conn)
|
||||
|
||||
ps, err := conn.Prepare(fmt.Sprintf("select null::%s", pgTypeName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Derefence value if it is a pointer
|
||||
derefZero := zero
|
||||
refVal := reflect.ValueOf(zero)
|
||||
if refVal.Kind() == reflect.Ptr {
|
||||
derefZero = refVal.Elem().Interface()
|
||||
}
|
||||
|
||||
result := reflect.New(reflect.TypeOf(derefZero))
|
||||
|
||||
err = ps.QueryRow().Scan(result.Interface())
|
||||
if err != nil {
|
||||
t.Errorf("%v %v", driverName, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(result.Elem().Interface(), derefZero) {
|
||||
t.Errorf("%s: did not convert null to zero", driverName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Package zeronull contains types that automatically convert between database NULLs and Go zero values.
|
||||
/*
|
||||
Sometimes the distinction between a zero value and a NULL value is not useful at the application level. For example,
|
||||
in PostgreSQL an empty string may be stored as NULL. There is usually no application level distinction between an
|
||||
empty string and a NULL string. Package zeronull implements types that seemlessly convert between PostgreSQL NULL and
|
||||
the zero value.
|
||||
|
||||
It is recommended to convert types at usage time rather than instantiate these types directly. In the example below,
|
||||
middlename would be stored as a NULL.
|
||||
|
||||
firstname := "John"
|
||||
middlename := ""
|
||||
lastname := "Smith"
|
||||
_, err := conn.Exec(
|
||||
ctx,
|
||||
"insert into people(firstname, middlename, lastname) values($1, $2, $3)",
|
||||
zeronull.Text(firstname),
|
||||
zeronull.Text(middlename),
|
||||
zeronull.Text(lastname),
|
||||
)
|
||||
*/
|
||||
package zeronull
|
|
@ -0,0 +1,90 @@
|
|||
package zeronull
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type Int2 int16
|
||||
|
||||
func (dst *Int2) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Int2
|
||||
err := nullable.DecodeText(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Int2(nullable.Int)
|
||||
} else {
|
||||
*dst = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dst *Int2) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Int2
|
||||
err := nullable.DecodeBinary(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Int2(nullable.Int)
|
||||
} else {
|
||||
*dst = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (src Int2) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Int2{
|
||||
Int: int16(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeText(ci, buf)
|
||||
}
|
||||
|
||||
func (src Int2) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Int2{
|
||||
Int: int16(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeBinary(ci, buf)
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dst *Int2) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*dst = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
var nullable pgtype.Int2
|
||||
err := nullable.Scan(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*dst = Int2(nullable.Int)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (src Int2) Value() (driver.Value, error) {
|
||||
return pgtype.EncodeValueText(src)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package zeronull_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgtype/testutil"
|
||||
"github.com/jackc/pgtype/zeronull"
|
||||
)
|
||||
|
||||
func TestInt2Transcode(t *testing.T) {
|
||||
testutil.TestSuccessfulTranscode(t, "int2", []interface{}{
|
||||
(zeronull.Int2)(1),
|
||||
(zeronull.Int2)(0),
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt2ConvertsGoZeroToNull(t *testing.T) {
|
||||
testutil.TestGoZeroToNullConversion(t, "int2", (zeronull.Int2)(0))
|
||||
}
|
||||
|
||||
func TestInt2ConvertsNullToGoZero(t *testing.T) {
|
||||
testutil.TestNullToGoZeroConversion(t, "int2", (zeronull.Int2)(0))
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package zeronull
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type Int4 int32
|
||||
|
||||
func (dst *Int4) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Int4
|
||||
err := nullable.DecodeText(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Int4(nullable.Int)
|
||||
} else {
|
||||
*dst = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dst *Int4) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Int4
|
||||
err := nullable.DecodeBinary(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Int4(nullable.Int)
|
||||
} else {
|
||||
*dst = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (src Int4) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Int4{
|
||||
Int: int32(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeText(ci, buf)
|
||||
}
|
||||
|
||||
func (src Int4) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Int4{
|
||||
Int: int32(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeBinary(ci, buf)
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dst *Int4) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*dst = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
var nullable pgtype.Int4
|
||||
err := nullable.Scan(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*dst = Int4(nullable.Int)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (src Int4) Value() (driver.Value, error) {
|
||||
return pgtype.EncodeValueText(src)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package zeronull_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgtype/testutil"
|
||||
"github.com/jackc/pgtype/zeronull"
|
||||
)
|
||||
|
||||
func TestInt4Transcode(t *testing.T) {
|
||||
testutil.TestSuccessfulTranscode(t, "int4", []interface{}{
|
||||
(zeronull.Int4)(1),
|
||||
(zeronull.Int4)(0),
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt4ConvertsGoZeroToNull(t *testing.T) {
|
||||
testutil.TestGoZeroToNullConversion(t, "int4", (zeronull.Int4)(0))
|
||||
}
|
||||
|
||||
func TestInt4ConvertsNullToGoZero(t *testing.T) {
|
||||
testutil.TestNullToGoZeroConversion(t, "int4", (zeronull.Int4)(0))
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package zeronull
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type Int8 int64
|
||||
|
||||
func (dst *Int8) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Int8
|
||||
err := nullable.DecodeText(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Int8(nullable.Int)
|
||||
} else {
|
||||
*dst = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dst *Int8) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Int8
|
||||
err := nullable.DecodeBinary(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Int8(nullable.Int)
|
||||
} else {
|
||||
*dst = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (src Int8) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Int8{
|
||||
Int: int64(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeText(ci, buf)
|
||||
}
|
||||
|
||||
func (src Int8) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Int8{
|
||||
Int: int64(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeBinary(ci, buf)
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dst *Int8) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*dst = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
var nullable pgtype.Int8
|
||||
err := nullable.Scan(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*dst = Int8(nullable.Int)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (src Int8) Value() (driver.Value, error) {
|
||||
return pgtype.EncodeValueText(src)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package zeronull_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgtype/testutil"
|
||||
"github.com/jackc/pgtype/zeronull"
|
||||
)
|
||||
|
||||
func TestInt8Transcode(t *testing.T) {
|
||||
testutil.TestSuccessfulTranscode(t, "int8", []interface{}{
|
||||
(zeronull.Int8)(1),
|
||||
(zeronull.Int8)(0),
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt8ConvertsGoZeroToNull(t *testing.T) {
|
||||
testutil.TestGoZeroToNullConversion(t, "int8", (zeronull.Int8)(0))
|
||||
}
|
||||
|
||||
func TestInt8ConvertsNullToGoZero(t *testing.T) {
|
||||
testutil.TestNullToGoZeroConversion(t, "int8", (zeronull.Int8)(0))
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package zeronull
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type Text string
|
||||
|
||||
func (dst *Text) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Text
|
||||
err := nullable.DecodeText(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Text(nullable.String)
|
||||
} else {
|
||||
*dst = Text("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dst *Text) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Text
|
||||
err := nullable.DecodeBinary(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Text(nullable.String)
|
||||
} else {
|
||||
*dst = Text("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (src Text) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == Text("") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Text{
|
||||
String: string(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeText(ci, buf)
|
||||
}
|
||||
|
||||
func (src Text) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if src == Text("") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Text{
|
||||
String: string(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeBinary(ci, buf)
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dst *Text) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*dst = Text("")
|
||||
return nil
|
||||
}
|
||||
|
||||
var nullable pgtype.Text
|
||||
err := nullable.Scan(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*dst = Text(nullable.String)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (src Text) Value() (driver.Value, error) {
|
||||
return pgtype.EncodeValueText(src)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package zeronull_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgtype/testutil"
|
||||
"github.com/jackc/pgtype/zeronull"
|
||||
)
|
||||
|
||||
func TestTextTranscode(t *testing.T) {
|
||||
testutil.TestSuccessfulTranscode(t, "text", []interface{}{
|
||||
(zeronull.Text)("foo"),
|
||||
(zeronull.Text)(""),
|
||||
})
|
||||
}
|
||||
|
||||
func TestTextConvertsGoZeroToNull(t *testing.T) {
|
||||
testutil.TestGoZeroToNullConversion(t, "text", (zeronull.Text)(""))
|
||||
}
|
||||
|
||||
func TestTextConvertsNullToGoZero(t *testing.T) {
|
||||
testutil.TestNullToGoZeroConversion(t, "text", (zeronull.Text)(""))
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package zeronull
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type Timestamp time.Time
|
||||
|
||||
func (dst *Timestamp) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Timestamp
|
||||
err := nullable.DecodeText(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Timestamp(nullable.Time)
|
||||
} else {
|
||||
*dst = Timestamp{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dst *Timestamp) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Timestamp
|
||||
err := nullable.DecodeBinary(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Timestamp(nullable.Time)
|
||||
} else {
|
||||
*dst = Timestamp{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (src Timestamp) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if (src == Timestamp{}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Timestamp{
|
||||
Time: time.Time(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeText(ci, buf)
|
||||
}
|
||||
|
||||
func (src Timestamp) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if (src == Timestamp{}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Timestamp{
|
||||
Time: time.Time(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeBinary(ci, buf)
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dst *Timestamp) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*dst = Timestamp{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var nullable pgtype.Timestamp
|
||||
err := nullable.Scan(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*dst = Timestamp(nullable.Time)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (src Timestamp) Value() (driver.Value, error) {
|
||||
return pgtype.EncodeValueText(src)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package zeronull_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgtype/testutil"
|
||||
"github.com/jackc/pgtype/zeronull"
|
||||
)
|
||||
|
||||
func TestTimestampTranscode(t *testing.T) {
|
||||
testutil.TestSuccessfulTranscodeEqFunc(t, "timestamp", []interface{}{
|
||||
(zeronull.Timestamp)(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
(zeronull.Timestamp)(time.Time{}),
|
||||
}, func(a, b interface{}) bool {
|
||||
at := a.(zeronull.Timestamp)
|
||||
bt := b.(zeronull.Timestamp)
|
||||
|
||||
return time.Time(at).Equal(time.Time(bt))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTimestampConvertsGoZeroToNull(t *testing.T) {
|
||||
testutil.TestGoZeroToNullConversion(t, "timestamp", (zeronull.Timestamp)(time.Time{}))
|
||||
}
|
||||
|
||||
func TestTimestampConvertsNullToGoZero(t *testing.T) {
|
||||
testutil.TestNullToGoZeroConversion(t, "timestamp", (zeronull.Timestamp)(time.Time{}))
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package zeronull
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type Timestamptz time.Time
|
||||
|
||||
func (dst *Timestamptz) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Timestamptz
|
||||
err := nullable.DecodeText(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Timestamptz(nullable.Time)
|
||||
} else {
|
||||
*dst = Timestamptz{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dst *Timestamptz) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.Timestamptz
|
||||
err := nullable.DecodeBinary(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = Timestamptz(nullable.Time)
|
||||
} else {
|
||||
*dst = Timestamptz{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (src Timestamptz) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if (src == Timestamptz{}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Timestamptz{
|
||||
Time: time.Time(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeText(ci, buf)
|
||||
}
|
||||
|
||||
func (src Timestamptz) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if (src == Timestamptz{}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.Timestamptz{
|
||||
Time: time.Time(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeBinary(ci, buf)
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dst *Timestamptz) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*dst = Timestamptz{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var nullable pgtype.Timestamptz
|
||||
err := nullable.Scan(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*dst = Timestamptz(nullable.Time)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (src Timestamptz) Value() (driver.Value, error) {
|
||||
return pgtype.EncodeValueText(src)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package zeronull_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgtype/testutil"
|
||||
"github.com/jackc/pgtype/zeronull"
|
||||
)
|
||||
|
||||
func TestTimestamptzTranscode(t *testing.T) {
|
||||
testutil.TestSuccessfulTranscodeEqFunc(t, "timestamptz", []interface{}{
|
||||
(zeronull.Timestamptz)(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
(zeronull.Timestamptz)(time.Time{}),
|
||||
}, func(a, b interface{}) bool {
|
||||
at := a.(zeronull.Timestamptz)
|
||||
bt := b.(zeronull.Timestamptz)
|
||||
|
||||
return time.Time(at).Equal(time.Time(bt))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTimestamptzConvertsGoZeroToNull(t *testing.T) {
|
||||
testutil.TestGoZeroToNullConversion(t, "timestamptz", (zeronull.Timestamptz)(time.Time{}))
|
||||
}
|
||||
|
||||
func TestTimestamptzConvertsNullToGoZero(t *testing.T) {
|
||||
testutil.TestNullToGoZeroConversion(t, "timestamptz", (zeronull.Timestamptz)(time.Time{}))
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package zeronull
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type UUID [16]byte
|
||||
|
||||
func (dst *UUID) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.UUID
|
||||
err := nullable.DecodeText(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = UUID(nullable.Bytes)
|
||||
} else {
|
||||
*dst = UUID{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dst *UUID) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
|
||||
var nullable pgtype.UUID
|
||||
err := nullable.DecodeBinary(ci, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nullable.Status == pgtype.Present {
|
||||
*dst = UUID(nullable.Bytes)
|
||||
} else {
|
||||
*dst = UUID{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (src UUID) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if (src == UUID{}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.UUID{
|
||||
Bytes: [16]byte(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeText(ci, buf)
|
||||
}
|
||||
|
||||
func (src UUID) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
|
||||
if (src == UUID{}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nullable := pgtype.UUID{
|
||||
Bytes: [16]byte(src),
|
||||
Status: pgtype.Present,
|
||||
}
|
||||
|
||||
return nullable.EncodeBinary(ci, buf)
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dst *UUID) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*dst = UUID{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var nullable pgtype.UUID
|
||||
err := nullable.Scan(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*dst = UUID(nullable.Bytes)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (src UUID) Value() (driver.Value, error) {
|
||||
return pgtype.EncodeValueText(src)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package zeronull_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgtype/testutil"
|
||||
"github.com/jackc/pgtype/zeronull"
|
||||
)
|
||||
|
||||
func TestUUIDTranscode(t *testing.T) {
|
||||
testutil.TestSuccessfulTranscode(t, "uuid", []interface{}{
|
||||
(*zeronull.UUID)(&[16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}),
|
||||
(*zeronull.UUID)(&[16]byte{}),
|
||||
})
|
||||
}
|
||||
|
||||
func TestUUIDConvertsGoZeroToNull(t *testing.T) {
|
||||
testutil.TestGoZeroToNullConversion(t, "uuid", (*zeronull.UUID)(&[16]byte{}))
|
||||
}
|
||||
|
||||
func TestUUIDConvertsNullToGoZero(t *testing.T) {
|
||||
testutil.TestNullToGoZeroConversion(t, "uuid", (*zeronull.UUID)(&[16]byte{}))
|
||||
}
|
Loading…
Reference in New Issue