diff --git a/name.go b/name.go new file mode 100644 index 00000000..3ff81f12 --- /dev/null +++ b/name.go @@ -0,0 +1,44 @@ +package pgtype + +import ( + "io" +) + +// Name is a type used for PostgreSQL's special 63-byte +// name data type, used for identifiers like table names. +// The pg_class.relname column is a good example of where the +// name data type is used. +// +// Note that the underlying Go data type of pgx.Name is string, +// so there is no way to enforce the 63-byte length. Inputting +// a longer name into PostgreSQL will result in silent truncation +// to 63 bytes. +// +// Also, if you have custom-compiled PostgreSQL and set +// NAMEDATALEN to a different value, obviously that number of +// bytes applies, rather than the default 63. +type Name Text + +func (dst *Name) ConvertFrom(src interface{}) error { + return (*Text)(dst).ConvertFrom(src) +} + +func (src *Name) AssignTo(dst interface{}) error { + return (*Text)(src).AssignTo(dst) +} + +func (dst *Name) DecodeText(r io.Reader) error { + return (*Text)(dst).DecodeText(r) +} + +func (dst *Name) DecodeBinary(r io.Reader) error { + return (*Text)(dst).DecodeBinary(r) +} + +func (src Name) EncodeText(w io.Writer) error { + return (Text)(src).EncodeText(w) +} + +func (src Name) EncodeBinary(w io.Writer) error { + return (Text)(src).EncodeBinary(w) +} diff --git a/name_test.go b/name_test.go new file mode 100644 index 00000000..c5f7de17 --- /dev/null +++ b/name_test.go @@ -0,0 +1,97 @@ +package pgtype_test + +import ( + "reflect" + "testing" + + "github.com/jackc/pgx/pgtype" +) + +func TestNameTranscode(t *testing.T) { + testSuccessfulTranscode(t, "name", []interface{}{ + pgtype.Name{String: "", Status: pgtype.Present}, + pgtype.Name{String: "foo", Status: pgtype.Present}, + pgtype.Name{Status: pgtype.Null}, + }) +} + +func TestNameConvertFrom(t *testing.T) { + successfulTests := []struct { + source interface{} + result pgtype.Name + }{ + {source: "foo", result: pgtype.Name{String: "foo", Status: pgtype.Present}}, + {source: _string("bar"), result: pgtype.Name{String: "bar", Status: pgtype.Present}}, + {source: (*string)(nil), result: pgtype.Name{Status: pgtype.Null}}, + } + + for i, tt := range successfulTests { + var d pgtype.Name + err := d.ConvertFrom(tt.source) + if err != nil { + t.Errorf("%d: %v", i, err) + } + + if d != tt.result { + t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, d) + } + } +} + +func TestNameAssignTo(t *testing.T) { + var s string + var ps *string + + simpleTests := []struct { + src pgtype.Name + dst interface{} + expected interface{} + }{ + {src: pgtype.Name{String: "foo", Status: pgtype.Present}, dst: &s, expected: "foo"}, + {src: pgtype.Name{Status: pgtype.Null}, dst: &ps, expected: ((*string)(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(); dst != tt.expected { + t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst) + } + } + + pointerAllocTests := []struct { + src pgtype.Name + dst interface{} + expected interface{} + }{ + {src: pgtype.Name{String: "foo", Status: pgtype.Present}, dst: &ps, expected: "foo"}, + } + + for i, tt := range pointerAllocTests { + err := tt.src.AssignTo(tt.dst) + if err != nil { + t.Errorf("%d: %v", i, err) + } + + if dst := reflect.ValueOf(tt.dst).Elem().Elem().Interface(); dst != tt.expected { + t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst) + } + } + + errorTests := []struct { + src pgtype.Name + dst interface{} + }{ + {src: pgtype.Name{Status: pgtype.Null}, dst: &s}, + } + + for i, tt := range errorTests { + err := tt.src.AssignTo(tt.dst) + if err == nil { + t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst) + } + } +}