Conform closer to database/sql style and add no rows test

scan-io
Jack Christensen 2014-07-11 08:16:21 -05:00
parent 566d713285
commit 01f261c71c
3 changed files with 48 additions and 20 deletions

23
conn.go
View File

@ -85,15 +85,9 @@ func (ct CommandTag) RowsAffected() int64 {
return n
}
// NotSingleRowError is returned when exactly 1 row is expected, but 0 or more than
// 1 row is returned
type NotSingleRowError struct {
RowCount int64
}
func (e NotSingleRowError) Error() string {
return fmt.Sprintf("Expected to find 1 row exactly, instead found %d", e.RowCount)
}
var ErrNoRows = errors.New("no rows in result set")
var ErrNotificationTimeout = errors.New("notification timeout")
var ErrDeadConn = errors.New("conn is dead")
type ProtocolError string
@ -101,9 +95,6 @@ func (e ProtocolError) Error() string {
return string(e)
}
var NotificationTimeoutError = errors.New("Notification Timeout")
var DeadConnError = errors.New("Connection is dead")
// Connect establishes a connection with a PostgreSQL server using config.
// config.Host must be specified. config.User will default to the OS user name.
// Other config fields are optional.
@ -340,7 +331,7 @@ func (c *Conn) Listen(channel string) (err error) {
}
// WaitForNotification waits for a PostgreSQL notification for up to timeout.
// If the timeout occurs it returns pgx.NotificationTimeoutError
// If the timeout occurs it returns pgx.ErrNotificationTimeout
func (c *Conn) WaitForNotification(timeout time.Duration) (*Notification, error) {
if len(c.notifications) > 0 {
notification := c.notifications[0]
@ -370,7 +361,7 @@ func (c *Conn) WaitForNotification(timeout time.Duration) (*Notification, error)
if err != nil {
c.conn.SetReadDeadline(zeroTime) // we can only return one error and we already have one -- so ignore possiple error from SetReadDeadline
if err, ok := err.(*net.OpError); ok && err.Timeout() {
return nil, NotificationTimeoutError
return nil, ErrNotificationTimeout
}
return nil, err
}
@ -417,7 +408,7 @@ func (r *Row) Scan(dest ...interface{}) (err error) {
if !qr.NextRow() {
if qr.Err() == nil {
return errors.New("No rows")
return ErrNoRows
} else {
return qr.Err()
}
@ -940,7 +931,7 @@ func (c *Conn) processContextFreeMsg(t byte, r *MsgReader) (err error) {
func (c *Conn) rxMsg() (t byte, r *MsgReader, err error) {
if !c.alive {
return 0, nil, DeadConnError
return 0, nil, ErrDeadConn
}
t, err = c.mr.rxMsg()

View File

@ -182,6 +182,20 @@ func TestConnectWithMD5Password(t *testing.T) {
}
}
func TestConnectWithConnectionRefused(t *testing.T) {
t.Parallel()
// Presumably nothing is listening on 127.0.0.1:1
bad := *defaultConnConfig
bad.Host = "127.0.0.1"
bad.Port = 1
_, err := pgx.Connect(bad)
if !strings.Contains(err.Error(), "connection refused") {
t.Fatal("Unable to establish connection: " + err.Error())
}
}
func TestParseURI(t *testing.T) {
t.Parallel()
@ -788,7 +802,7 @@ func TestListenNotify(t *testing.T) {
// when timeout occurs
notification, err = listener.WaitForNotification(time.Millisecond)
if err != pgx.NotificationTimeoutError {
if err != pgx.ErrNotificationTimeout {
t.Errorf("WaitForNotification returned the wrong kind of error: %v", err)
}
if notification != nil {
@ -1066,6 +1080,27 @@ func TestQueryRowPreparedErrors(t *testing.T) {
}
}
func TestQueryRowNoResults(t *testing.T) {
t.Parallel()
conn := mustConnect(t, *defaultConnConfig)
defer closeConn(t, conn)
sql := "select 1 where 1=0"
psName := "selectNothing"
mustPrepare(t, conn, psName, sql)
for _, sql := range []string{sql, psName} {
var n int32
err := conn.QueryRow(sql).Scan(&n)
if err != pgx.ErrNoRows {
t.Errorf("Expected pgx.ErrNoRows, got %v", err)
}
ensureConnValid(t, conn)
}
}
func TestQueryPreparedEncodeError(t *testing.T) {
t.Parallel()

View File

@ -45,11 +45,13 @@ func afterConnect(conn *pgx.Conn) (err error) {
func getUrlHandler(w http.ResponseWriter, req *http.Request) {
var url string
if err := pool.QueryRow("getUrl", req.URL.Path).Scan(&url); err == nil {
err := pool.QueryRow("getUrl", req.URL.Path).Scan(&url)
switch err {
case nil:
http.Redirect(w, req, url, http.StatusSeeOther)
} else if _, ok := err.(pgx.NotSingleRowError); ok {
case pgx.ErrNoRows:
http.NotFound(w, req)
} else {
default:
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
}