pgx/record_test.go
Jack Christensen 6e21cb00fe Add pgtype.Record and prerequisite restructuring
Because reading a record type requires the decoder to be able to look up oid
to type mapping and types such as hstore have types that are not fixed between
different PostgreSQL servers it was necessary to restructure the pgtype system
so all encoders and decodes take a *ConnInfo that includes oid/name/type
information.
2017-03-18 12:01:16 -05:00

151 lines
3.4 KiB
Go

package pgtype_test
import (
"fmt"
"reflect"
"testing"
"github.com/jackc/pgx"
"github.com/jackc/pgx/pgtype"
)
func TestRecordTranscode(t *testing.T) {
conn := mustConnectPgx(t)
defer mustClose(t, conn)
tests := []struct {
sql string
expected pgtype.Record
}{
{
sql: `select row()`,
expected: pgtype.Record{
Fields: []pgtype.Value{},
Status: pgtype.Present,
},
},
{
sql: `select row('foo'::text, 42::int4)`,
expected: pgtype.Record{
Fields: []pgtype.Value{
&pgtype.Text{String: "foo", Status: pgtype.Present},
&pgtype.Int4{Int: 42, Status: pgtype.Present},
},
Status: pgtype.Present,
},
},
{
sql: `select row('foo'::text, array[1, 2, null, 4]::int4[], 42::int4)`,
expected: pgtype.Record{
Fields: []pgtype.Value{
&pgtype.Text{String: "foo", Status: pgtype.Present},
&pgtype.Int4Array{
Elements: []pgtype.Int4{
pgtype.Int4{Int: 1, Status: pgtype.Present},
pgtype.Int4{Int: 2, Status: pgtype.Present},
pgtype.Int4{Status: pgtype.Null},
pgtype.Int4{Int: 4, Status: pgtype.Present},
},
Dimensions: []pgtype.ArrayDimension{{Length: 4, LowerBound: 1}},
Status: pgtype.Present,
},
&pgtype.Int4{Int: 42, Status: pgtype.Present},
},
Status: pgtype.Present,
},
},
{
sql: `select row(null)`,
expected: pgtype.Record{
Fields: []pgtype.Value{
&pgtype.Unknown{Status: pgtype.Null},
},
Status: pgtype.Present,
},
},
{
sql: `select null::record`,
expected: pgtype.Record{
Status: pgtype.Null,
},
},
}
for i, tt := range tests {
psName := fmt.Sprintf("test%d", i)
ps, err := conn.Prepare(psName, tt.sql)
if err != nil {
t.Fatal(err)
}
ps.FieldDescriptions[0].FormatCode = pgx.BinaryFormatCode
var result pgtype.Record
if err := conn.QueryRow(psName).Scan(&result); err != nil {
t.Errorf("%d: %v", i, err)
continue
}
if !reflect.DeepEqual(tt.expected, result) {
t.Errorf("%d: expected %v, got %v", i, tt.expected, result)
}
}
}
func TestRecordAssignTo(t *testing.T) {
var valueSlice []pgtype.Value
var interfaceSlice []interface{}
simpleTests := []struct {
src pgtype.Record
dst interface{}
expected interface{}
}{
{
src: pgtype.Record{
Fields: []pgtype.Value{
&pgtype.Text{String: "foo", Status: pgtype.Present},
&pgtype.Int4{Int: 42, Status: pgtype.Present},
},
Status: pgtype.Present,
},
dst: &valueSlice,
expected: []pgtype.Value{
&pgtype.Text{String: "foo", Status: pgtype.Present},
&pgtype.Int4{Int: 42, Status: pgtype.Present},
},
},
{
src: pgtype.Record{
Fields: []pgtype.Value{
&pgtype.Text{String: "foo", Status: pgtype.Present},
&pgtype.Int4{Int: 42, Status: pgtype.Present},
},
Status: pgtype.Present,
},
dst: &interfaceSlice,
expected: []interface{}{"foo", int32(42)},
},
{
src: pgtype.Record{Status: pgtype.Null},
dst: &valueSlice,
expected: (([]pgtype.Value)(nil)),
},
{
src: pgtype.Record{Status: pgtype.Null},
dst: &interfaceSlice,
expected: (([]interface{})(nil)),
},
}
for i, tt := range simpleTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if dst := reflect.ValueOf(tt.dst).Elem().Interface(); !reflect.DeepEqual(dst, tt.expected) {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
}
}
}