Skip to content

Commit

Permalink
feat(spanner): add support of checking row not found errors from Read…
Browse files Browse the repository at this point in the history
…Row and ReadRowUsingIndex (#10405)

* feat(spanner): add support of checking row not found errors from ReadRow and ReadRowUsingIndex

* incorporate suggestions

* fix error message

* fix error message
  • Loading branch information
rahul2393 authored Jun 21, 2024
1 parent 1d28ac6 commit 5cb0c26
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
6 changes: 6 additions & 0 deletions spanner/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package spanner

import (
"context"
"errors"
"fmt"

"github.com/googleapis/gax-go/v2/apierror"
Expand All @@ -26,6 +27,11 @@ import (
"google.golang.org/grpc/status"
)

var (
// ErrRowNotFound row not found error
ErrRowNotFound = errors.New("row not found")
)

// Error is the structured error returned by Cloud Spanner client.
//
// Deprecated: Unwrap any error that is returned by the Spanner client as an APIError
Expand Down
6 changes: 6 additions & 0 deletions spanner/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1731,6 +1731,9 @@ func TestIntegration_Reads(t *testing.T) {
if ErrCode(err) != codes.NotFound {
t.Fatalf("got %v, want NotFound", err)
}
if !errors.Is(err, ErrRowNotFound) {
t.Fatalf("got %v, want spanner.ErrRowNotFound", err)
}
verifyDirectPathRemoteAddress(t)

// Index point read.
Expand All @@ -1751,6 +1754,9 @@ func TestIntegration_Reads(t *testing.T) {
if ErrCode(err) != codes.NotFound {
t.Fatalf("got %v, want NotFound", err)
}
if !errors.Is(err, ErrRowNotFound) {
t.Fatalf("got %v, want spanner.ErrRowNotFound", err)
}
verifyDirectPathRemoteAddress(t)
rangeReads(ctx, t, client)
indexRangeReads(ctx, t, client)
Expand Down
30 changes: 26 additions & 4 deletions spanner/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,16 @@ func (t *txReadOnly) ReadWithOptions(ctx context.Context, table string, keys Key
// errRowNotFound returns error for not being able to read the row identified by
// key.
func errRowNotFound(table string, key Key) error {
return spannerErrorf(codes.NotFound, "row not found(Table: %v, PrimaryKey: %v)", table, key)
err := spannerErrorf(codes.NotFound, "row not found(Table: %v, PrimaryKey: %v)", table, key)
err.(*Error).err = ErrRowNotFound
return err
}

// errRowNotFoundByIndex returns error for not being able to read the row by index.
func errRowNotFoundByIndex(table string, key Key, index string) error {
return spannerErrorf(codes.NotFound, "row not found(Table: %v, IndexKey: %v, Index: %v)", table, key, index)
err := spannerErrorf(codes.NotFound, "row not found(Table: %v, IndexKey: %v, Index: %v)", table, key, index)
err.(*Error).err = ErrRowNotFound
return err
}

// errMultipleRowsFound returns error for receiving more than one row when reading a single row using an index.
Expand All @@ -346,8 +350,14 @@ func errInlineBeginTransactionFailed() error {

// ReadRow reads a single row from the database.
//
// If no row is present with the given key, then ReadRow returns an error where
// If no row is present with the given key, then ReadRow returns an error(spanner.ErrRowNotFound) where
// spanner.ErrCode(err) is codes.NotFound.
//
// To check if the error is spanner.ErrRowNotFound:
//
// if errors.Is(err, spanner.ErrRowNotFound) {
// ...
// }
func (t *txReadOnly) ReadRow(ctx context.Context, table string, key Key, columns []string) (*Row, error) {
return t.ReadRowWithOptions(ctx, table, key, columns, nil)
}
Expand All @@ -356,6 +366,12 @@ func (t *txReadOnly) ReadRow(ctx context.Context, table string, key Key, columns
//
// If no row is present with the given key, then ReadRowWithOptions returns an error where
// spanner.ErrCode(err) is codes.NotFound.
//
// To check if the error is spanner.ErrRowNotFound:
//
// if errors.Is(err, spanner.ErrRowNotFound) {
// ...
// }
func (t *txReadOnly) ReadRowWithOptions(ctx context.Context, table string, key Key, columns []string, opts *ReadOptions) (*Row, error) {
iter := t.ReadWithOptions(ctx, table, key, columns, opts)
defer iter.Stop()
Expand All @@ -373,7 +389,13 @@ func (t *txReadOnly) ReadRowWithOptions(ctx context.Context, table string, key K
// ReadRowUsingIndex reads a single row from the database using an index.
//
// If no row is present with the given index, then ReadRowUsingIndex returns an
// error where spanner.ErrCode(err) is codes.NotFound.
// error(spanner.ErrRowNotFound) where spanner.ErrCode(err) is codes.NotFound.
//
// To check if the error is spanner.ErrRowNotFound:
//
// if errors.Is(err, spanner.ErrRowNotFound) {
// ...
// }
//
// If more than one row received with the given index, then ReadRowUsingIndex
// returns an error where spanner.ErrCode(err) is codes.FailedPrecondition.
Expand Down

0 comments on commit 5cb0c26

Please sign in to comment.