pgtype.JSON(B).Value now returns []byte

Allows scanning jsonb column into *json.RawMessage.

fixes #409
pull/414/head
Jack Christensen 2018-04-14 09:17:56 -05:00
parent 6556ef67cb
commit 5297846239
5 changed files with 58 additions and 1 deletions

View File

@ -12,6 +12,13 @@
* Fix StartReplication() syntax (steampunkcoder)
* Fix precision loss for test format geometric types
## Changes
* pgtype.JSON(B).Value now returns []byte instead of string. This allows
database/sql to scan json(b) into \*json.RawMessage. This is a tiny behavior
change, but database/sql Scan should automatically convert []byte to string, so
there shouldn't be any incompatibility.
# 3.1.0 (January 15, 2018)
## Features

View File

@ -152,7 +152,7 @@ func (dst *JSON) Scan(src interface{}) error {
func (src *JSON) Value() (driver.Value, error) {
switch src.Status {
case Present:
return string(src.Bytes), nil
return src.Bytes, nil
case Null:
return nil, nil
default:

View File

@ -495,6 +495,10 @@ func (r *Rows) Next(dest []driver.Value) error {
r.values[i] = &pgtype.Int4{}
case pgtype.Int8OID:
r.values[i] = &pgtype.Int8{}
case pgtype.JSONOID:
r.values[i] = &pgtype.JSON{}
case pgtype.JSONBOID:
r.values[i] = &pgtype.JSONB{}
case pgtype.OIDOID:
r.values[i] = &pgtype.OIDValue{}
case pgtype.TimestampOID:

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"database/sql"
"encoding/json"
"fmt"
"math"
"reflect"
@ -1466,3 +1467,22 @@ func TestSimpleQueryLifeCycle(t *testing.T) {
ensureConnValid(t, db)
}
// https://github.com/jackc/pgx/issues/409
func TestScanJSONIntoJSONRawMessage(t *testing.T) {
db := openDB(t)
defer closeDB(t, db)
var msg json.RawMessage
err := db.QueryRow("select '{}'::jsonb").Scan(&msg)
if err != nil {
t.Fatalf("QueryRow / Scan failed: %v", err)
}
if bytes.Compare([]byte("{}"), []byte(msg)) != 0 {
t.Fatalf("Expected %v, got %v", []byte("{}"), msg)
}
ensureConnValid(t, db)
}

View File

@ -31,6 +31,32 @@ func convertSimpleArgument(ci *pgtype.ConnInfo, arg interface{}) (interface{}, e
}
switch arg := arg.(type) {
// https://github.com/jackc/pgx/issues/409 Changed JSON and JSONB to surface
// []byte to database/sql instead of string. But that caused problems with the
// simple protocol because the driver.Valuer case got taken before the
// pgtype.TextEncoder case. And driver.Valuer needed to be first in the usual
// case because of https://github.com/jackc/pgx/issues/339. So instead we
// special case JSON and JSONB.
case *pgtype.JSON:
buf, err := arg.EncodeText(ci, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
case *pgtype.JSONB:
buf, err := arg.EncodeText(ci, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
case driver.Valuer:
return callValuerValue(arg)
case pgtype.TextEncoder: