summaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc/pgx/v5/rows.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/jackc/pgx/v5/rows.go')
-rw-r--r--vendor/github.com/jackc/pgx/v5/rows.go76
1 files changed, 57 insertions, 19 deletions
diff --git a/vendor/github.com/jackc/pgx/v5/rows.go b/vendor/github.com/jackc/pgx/v5/rows.go
index 1b1c8ac9a..73efffa0a 100644
--- a/vendor/github.com/jackc/pgx/v5/rows.go
+++ b/vendor/github.com/jackc/pgx/v5/rows.go
@@ -8,7 +8,6 @@ import (
"strings"
"time"
- "github.com/jackc/pgx/v5/internal/stmtcache"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgtype"
)
@@ -17,7 +16,8 @@ import (
// the *Conn can be used again. Rows are closed by explicitly calling Close(),
// calling Next() until it returns false, or when a fatal error occurs.
//
-// Once a Rows is closed the only methods that may be called are Close(), Err(), and CommandTag().
+// Once a Rows is closed the only methods that may be called are Close(), Err(),
+// and CommandTag().
//
// Rows is an interface instead of a struct to allow tests to mock Query. However,
// adding a method to an interface is technically a breaking change. Because of this
@@ -41,8 +41,15 @@ type Rows interface {
FieldDescriptions() []pgconn.FieldDescription
// Next prepares the next row for reading. It returns true if there is another
- // row and false if no more rows are available. It automatically closes rows
- // when all rows are read.
+ // row and false if no more rows are available or a fatal error has occurred.
+ // It automatically closes rows when all rows are read.
+ //
+ // Callers should check rows.Err() after rows.Next() returns false to detect
+ // whether result-set reading ended prematurely due to an error. See
+ // Conn.Query for details.
+ //
+ // For simpler error handling, consider using the higher-level pgx v5
+ // CollectRows() and ForEachRow() helpers instead.
Next() bool
// Scan reads the values from the current row into dest values positionally.
@@ -166,14 +173,12 @@ func (rows *baseRows) Close() {
}
if rows.err != nil && rows.conn != nil && rows.sql != "" {
- if stmtcache.IsStatementInvalid(rows.err) {
- if sc := rows.conn.statementCache; sc != nil {
- sc.Invalidate(rows.sql)
- }
+ if sc := rows.conn.statementCache; sc != nil {
+ sc.Invalidate(rows.sql)
+ }
- if sc := rows.conn.descriptionCache; sc != nil {
- sc.Invalidate(rows.sql)
- }
+ if sc := rows.conn.descriptionCache; sc != nil {
+ sc.Invalidate(rows.sql)
}
}
@@ -457,6 +462,39 @@ func CollectOneRow[T any](rows Rows, fn RowToFunc[T]) (T, error) {
return value, rows.Err()
}
+// CollectExactlyOneRow calls fn for the first row in rows and returns the result.
+// - If no rows are found returns an error where errors.Is(ErrNoRows) is true.
+// - If more than 1 row is found returns an error where errors.Is(ErrTooManyRows) is true.
+func CollectExactlyOneRow[T any](rows Rows, fn RowToFunc[T]) (T, error) {
+ defer rows.Close()
+
+ var (
+ err error
+ value T
+ )
+
+ if !rows.Next() {
+ if err = rows.Err(); err != nil {
+ return value, err
+ }
+
+ return value, ErrNoRows
+ }
+
+ value, err = fn(rows)
+ if err != nil {
+ return value, err
+ }
+
+ if rows.Next() {
+ var zero T
+
+ return zero, ErrTooManyRows
+ }
+
+ return value, rows.Err()
+}
+
// RowTo returns a T scanned from row.
func RowTo[T any](row CollectableRow) (T, error) {
var value T
@@ -496,7 +534,7 @@ func (rs *mapRowScanner) ScanRow(rows Rows) error {
}
// RowToStructByPos returns a T scanned from row. T must be a struct. T must have the same number a public fields as row
-// has fields. The row and T fields will by matched by position. If the "db" struct tag is "-" then the field will be
+// has fields. The row and T fields will be matched by position. If the "db" struct tag is "-" then the field will be
// ignored.
func RowToStructByPos[T any](row CollectableRow) (T, error) {
var value T
@@ -505,7 +543,7 @@ func RowToStructByPos[T any](row CollectableRow) (T, error) {
}
// RowToAddrOfStructByPos returns the address of a T scanned from row. T must be a struct. T must have the same number a
-// public fields as row has fields. The row and T fields will by matched by position. If the "db" struct tag is "-" then
+// public fields as row has fields. The row and T fields will be matched by position. If the "db" struct tag is "-" then
// the field will be ignored.
func RowToAddrOfStructByPos[T any](row CollectableRow) (*T, error) {
var value T
@@ -560,7 +598,7 @@ func (rs *positionalStructRowScanner) appendScanTargets(dstElemValue reflect.Val
}
// RowToStructByName returns a T scanned from row. T must be a struct. T must have the same number of named public
-// fields as row has fields. The row and T fields will by matched by name. The match is case-insensitive. The database
+// fields as row has fields. The row and T fields will be matched by name. The match is case-insensitive. The database
// column name can be overridden with a "db" struct tag. If the "db" struct tag is "-" then the field will be ignored.
func RowToStructByName[T any](row CollectableRow) (T, error) {
var value T
@@ -569,7 +607,7 @@ func RowToStructByName[T any](row CollectableRow) (T, error) {
}
// RowToAddrOfStructByName returns the address of a T scanned from row. T must be a struct. T must have the same number
-// of named public fields as row has fields. The row and T fields will by matched by name. The match is
+// of named public fields as row has fields. The row and T fields will be matched by name. The match is
// case-insensitive. The database column name can be overridden with a "db" struct tag. If the "db" struct tag is "-"
// then the field will be ignored.
func RowToAddrOfStructByName[T any](row CollectableRow) (*T, error) {
@@ -579,7 +617,7 @@ func RowToAddrOfStructByName[T any](row CollectableRow) (*T, error) {
}
// RowToStructByNameLax returns a T scanned from row. T must be a struct. T must have greater than or equal number of named public
-// fields as row has fields. The row and T fields will by matched by name. The match is case-insensitive. The database
+// fields as row has fields. The row and T fields will be matched by name. The match is case-insensitive. The database
// column name can be overridden with a "db" struct tag. If the "db" struct tag is "-" then the field will be ignored.
func RowToStructByNameLax[T any](row CollectableRow) (T, error) {
var value T
@@ -588,7 +626,7 @@ func RowToStructByNameLax[T any](row CollectableRow) (T, error) {
}
// RowToAddrOfStructByNameLax returns the address of a T scanned from row. T must be a struct. T must have greater than or
-// equal number of named public fields as row has fields. The row and T fields will by matched by name. The match is
+// equal number of named public fields as row has fields. The row and T fields will be matched by name. The match is
// case-insensitive. The database column name can be overridden with a "db" struct tag. If the "db" struct tag is "-"
// then the field will be ignored.
func RowToAddrOfStructByNameLax[T any](row CollectableRow) (*T, error) {
@@ -650,7 +688,7 @@ func (rs *namedStructRowScanner) appendScanTargets(dstElemValue reflect.Value, s
// Field is unexported, skip it.
continue
}
- // Handle anoymous struct embedding, but do not try to handle embedded pointers.
+ // Handle anonymous struct embedding, but do not try to handle embedded pointers.
if sf.Anonymous && sf.Type.Kind() == reflect.Struct {
scanTargets, err = rs.appendScanTargets(dstElemValue.Field(i), scanTargets, fldDescs)
if err != nil {
@@ -659,7 +697,7 @@ func (rs *namedStructRowScanner) appendScanTargets(dstElemValue reflect.Value, s
} else {
dbTag, dbTagPresent := sf.Tag.Lookup(structTagKey)
if dbTagPresent {
- dbTag = strings.Split(dbTag, ",")[0]
+ dbTag, _, _ = strings.Cut(dbTag, ",")
}
if dbTag == "-" {
// Field is ignored, skip it.