2
0
Files
pgx/hstore_array_test.go
T
Jack Christensen 6161728ff9 Prepare takes context
Also remove PrepareEx. It's primary usage was for context. Supplying
parameter OIDs is unnecessary when you can type cast in the query SQL.
If it does become necessary or desirable to add options back it can be
added in a backwards compatible way by adding a varargs as last
argument.
2019-04-20 11:47:16 -05:00

200 lines
6.1 KiB
Go

package pgtype_test
import (
"context"
"reflect"
"testing"
"github.com/jackc/pgx"
"github.com/jackc/pgx/pgtype"
"github.com/jackc/pgx/pgtype/testutil"
)
func TestHstoreArrayTranscode(t *testing.T) {
conn := testutil.MustConnectPgx(t)
defer testutil.MustCloseContext(t, conn)
var hstoreOID pgtype.OID
err := conn.QueryRow(context.Background(), "select t.oid from pg_type t where t.typname='hstore';").Scan(&hstoreOID)
if err != nil {
t.Fatalf("did not find hstore OID, %v", err)
}
conn.ConnInfo.RegisterDataType(pgtype.DataType{Value: &pgtype.Hstore{}, Name: "hstore", OID: hstoreOID})
var hstoreArrayOID pgtype.OID
err = conn.QueryRow(context.Background(), "select t.oid from pg_type t where t.typname='_hstore';").Scan(&hstoreArrayOID)
if err != nil {
t.Fatalf("did not find _hstore OID, %v", err)
}
conn.ConnInfo.RegisterDataType(pgtype.DataType{Value: &pgtype.HstoreArray{}, Name: "_hstore", OID: hstoreArrayOID})
text := func(s string) pgtype.Text {
return pgtype.Text{String: s, Status: pgtype.Present}
}
values := []pgtype.Hstore{
{Map: map[string]pgtype.Text{}, Status: pgtype.Present},
{Map: map[string]pgtype.Text{"foo": text("bar")}, Status: pgtype.Present},
{Map: map[string]pgtype.Text{"foo": text("bar"), "baz": text("quz")}, Status: pgtype.Present},
{Map: map[string]pgtype.Text{"NULL": text("bar")}, Status: pgtype.Present},
{Map: map[string]pgtype.Text{"foo": text("NULL")}, Status: pgtype.Present},
{Status: pgtype.Null},
}
specialStrings := []string{
`"`,
`'`,
`\`,
`\\`,
`=>`,
` `,
`\ / / \\ => " ' " '`,
}
for _, s := range specialStrings {
// Special key values
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{s + "foo": text("bar")}, Status: pgtype.Present}) // at beginning
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s + "bar": text("bar")}, Status: pgtype.Present}) // in middle
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s: text("bar")}, Status: pgtype.Present}) // at end
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{s: text("bar")}, Status: pgtype.Present}) // is key
// Special value values
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s + "bar")}, Status: pgtype.Present}) // at beginning
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s + "bar")}, Status: pgtype.Present}) // in middle
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s)}, Status: pgtype.Present}) // at end
values = append(values, pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s)}, Status: pgtype.Present}) // is key
}
src := &pgtype.HstoreArray{
Elements: values,
Dimensions: []pgtype.ArrayDimension{{Length: int32(len(values)), LowerBound: 1}},
Status: pgtype.Present,
}
ps, err := conn.Prepare(context.Background(), "test", "select $1::hstore[]")
if err != nil {
t.Fatal(err)
}
formats := []struct {
name string
formatCode int16
}{
{name: "TextFormat", formatCode: pgx.TextFormatCode},
{name: "BinaryFormat", formatCode: pgx.BinaryFormatCode},
}
for _, fc := range formats {
ps.FieldDescriptions[0].FormatCode = fc.formatCode
vEncoder := testutil.ForceEncoder(src, fc.formatCode)
if vEncoder == nil {
t.Logf("%#v does not implement %v", src, fc.name)
continue
}
var result pgtype.HstoreArray
err := conn.QueryRow(context.Background(), "test", vEncoder).Scan(&result)
if err != nil {
t.Errorf("%v: %v", fc.name, err)
continue
}
if result.Status != src.Status {
t.Errorf("%v: expected Status %v, got %v", fc.formatCode, src.Status, result.Status)
continue
}
if len(result.Elements) != len(src.Elements) {
t.Errorf("%v: expected %v elements, got %v", fc.formatCode, len(src.Elements), len(result.Elements))
continue
}
for i := range result.Elements {
a := src.Elements[i]
b := result.Elements[i]
if a.Status != b.Status {
t.Errorf("%v element idx %d: expected status %v, got %v", fc.formatCode, i, a.Status, b.Status)
}
if len(a.Map) != len(b.Map) {
t.Errorf("%v element idx %d: expected %v pairs, got %v", fc.formatCode, i, len(a.Map), len(b.Map))
}
for k := range a.Map {
if a.Map[k] != b.Map[k] {
t.Errorf("%v element idx %d: expected key %v to be %v, got %v", fc.formatCode, i, k, a.Map[k], b.Map[k])
}
}
}
}
}
func TestHstoreArraySet(t *testing.T) {
successfulTests := []struct {
src []map[string]string
result pgtype.HstoreArray
}{
{
src: []map[string]string{{"foo": "bar"}},
result: pgtype.HstoreArray{
Elements: []pgtype.Hstore{
{
Map: map[string]pgtype.Text{"foo": {String: "bar", Status: pgtype.Present}},
Status: pgtype.Present,
},
},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
},
}
for i, tt := range successfulTests {
var dst pgtype.HstoreArray
err := dst.Set(tt.src)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if !reflect.DeepEqual(dst, tt.result) {
t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.src, tt.result, dst)
}
}
}
func TestHstoreArrayAssignTo(t *testing.T) {
var m []map[string]string
simpleTests := []struct {
src pgtype.HstoreArray
dst *[]map[string]string
expected []map[string]string
}{
{
src: pgtype.HstoreArray{
Elements: []pgtype.Hstore{
{
Map: map[string]pgtype.Text{"foo": {String: "bar", Status: pgtype.Present}},
Status: pgtype.Present,
},
},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &m,
expected: []map[string]string{{"foo": "bar"}}},
{src: pgtype.HstoreArray{Status: pgtype.Null}, dst: &m, expected: (([]map[string]string)(nil))},
}
for i, tt := range simpleTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if !reflect.DeepEqual(*tt.dst, tt.expected) {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, *tt.dst)
}
}
}