From 06ec41c14db8119873ff00415f41a78d3432f006 Mon Sep 17 00:00:00 2001 From: Vojtech Vitek Date: Mon, 3 Jun 2024 12:45:07 +0200 Subject: [PATCH] Ignore scany errors on unknown columns Fixes this error: scany: column: 'new_field': no corresponding field found, or it's unexported in data.Collection --- pgkit.go | 19 ++++++++++++++++++- querier.go | 9 +++++---- tests/pgkit_test.go | 17 ++++++++--------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/pgkit.go b/pgkit.go index 9b3c983..aee2a18 100644 --- a/pgkit.go +++ b/pgkit.go @@ -7,6 +7,8 @@ import ( "time" sq "github.com/Masterminds/squirrel" + "github.com/georgysavva/scany/v2/dbscan" + "github.com/georgysavva/scany/v2/pgxscan" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/stdlib" @@ -78,7 +80,22 @@ func ConnectWithPGX(appName string, pgxConfig *pgxpool.Config) (*DB, error) { } db.SQL = &StatementBuilder{StatementBuilderType: sq.StatementBuilder.PlaceholderFormat(sq.Dollar)} - db.Query = &Querier{pool: db.Conn, SQL: db.SQL} + + // TODO: It might be handy to let developers disable this option in "dev" mode. However, + // true is a good default value, see https://github.com/goware/pgkit/issues/13. + allowUnknownColumns := true + + dbScanAPI, err := pgxscan.NewDBScanAPI(dbscan.WithAllowUnknownColumns(allowUnknownColumns)) + if err != nil { + return nil, wrapErr(err) + } + + pgxScanAPI, err := pgxscan.NewAPI(dbScanAPI) + if err != nil { + return nil, wrapErr(err) + } + + db.Query = &Querier{pool: db.Conn, Scan: pgxScanAPI, SQL: db.SQL} return db, nil } diff --git a/querier.go b/querier.go index 12d6f3a..eb12e12 100644 --- a/querier.go +++ b/querier.go @@ -16,6 +16,7 @@ import ( type Querier struct { pool *pgxpool.Pool tx pgx.Tx + Scan *pgxscan.API SQL *StatementBuilder } @@ -90,7 +91,7 @@ func (q *Querier) GetAll(ctx context.Context, query Sqlizer, dest interface{}) e if err != nil { return wrapErr(err) } - return wrapErr(pgxscan.ScanAll(dest, rows)) + return wrapErr(q.Scan.ScanAll(dest, rows)) } func (q *Querier) GetOne(ctx context.Context, query Sqlizer, dest interface{}) error { @@ -105,7 +106,7 @@ func (q *Querier) GetOne(ctx context.Context, query Sqlizer, dest interface{}) e if err != nil { return wrapErr(err) } - return wrapErr(pgxscan.ScanOne(dest, rows)) + return wrapErr(q.Scan.ScanOne(dest, rows)) } func (q *Querier) BatchExec(ctx context.Context, queries Queries) ([]pgconn.CommandTag, error) { @@ -197,7 +198,7 @@ func (q *Querier) BatchQuery(ctx context.Context, queries Queries) (pgx.BatchRes // defer batchResults.Close() // // for i, rows := range batchRows { -// // err := pgxscan.ScanAll(dest[i], rows) +// // err := q.scan.ScanAll(dest[i], rows) // // if err != nil { // // return wrapErr(err) // // } @@ -208,7 +209,7 @@ func (q *Querier) BatchQuery(ctx context.Context, queries Queries) (pgx.BatchRes // if err != nil { // return wrapErr(err) // } -// err = pgxscan.ScanAll(dest, rows) +// err = q.scan.ScanAll(dest, rows) // if err != nil { // return wrapErr(err) // } diff --git a/tests/pgkit_test.go b/tests/pgkit_test.go index e7bcc96..23f4f1d 100644 --- a/tests/pgkit_test.go +++ b/tests/pgkit_test.go @@ -10,7 +10,6 @@ import ( "testing" sq "github.com/Masterminds/squirrel" - "github.com/georgysavva/scany/v2/pgxscan" "github.com/goware/pgkit/v2" "github.com/goware/pgkit/v2/db" "github.com/goware/pgkit/v2/dbtype" @@ -81,7 +80,7 @@ func TestInsertAndSelectRows(t *testing.T) { selectq, args := DB.SQL.Select("*").From("accounts").MustSql() var accounts []*Account - err = pgxscan.Select(context.Background(), DB.Conn, &accounts, selectq, args...) + err = DB.Query.Scan.Select(context.Background(), DB.Conn, &accounts, selectq, args...) require.NoError(t, err) require.Len(t, accounts, 1) @@ -181,7 +180,7 @@ func TestInsertAndSelectRecords(t *testing.T) { // Scan result into *Account object a := &Account{} - err = pgxscan.ScanOne(a, rows) + err = DB.Query.Scan.ScanOne(a, rows) assert.NoError(t, err) assert.True(t, a.ID != 0) @@ -215,7 +214,7 @@ func TestQueryWithNoResults(t *testing.T) { // shorthand { - err = pgxscan.Select(context.Background(), DB.Conn, &accounts, selectq, args...) + err = DB.Query.Scan.Select(context.Background(), DB.Conn, &accounts, selectq, args...) assert.NoError(t, err) assert.Len(t, accounts, 0) } @@ -226,7 +225,7 @@ func TestQueryWithNoResults(t *testing.T) { defer rows.Close() assert.NoError(t, err) - err = pgxscan.ScanAll(&accounts, rows) + err = DB.Query.Scan.ScanAll(&accounts, rows) assert.NoError(t, err) assert.Len(t, accounts, 0) @@ -235,7 +234,7 @@ func TestQueryWithNoResults(t *testing.T) { // scan one -- returning 'no rows' error { var a *Account - err = pgxscan.Get(context.Background(), DB.Conn, a, selectq, args...) + err = DB.Query.Scan.Get(context.Background(), DB.Conn, a, selectq, args...) assert.True(t, errors.Is(err, pgx.ErrNoRows)) } } @@ -677,7 +676,7 @@ func TestBatchQuery(t *testing.T) { require.NoError(t, err) var account Account - err = pgxscan.ScanOne(&account, rows) + err = DB.Query.Scan.ScanOne(&account, rows) require.NoError(t, err) accounts = append(accounts, &account) } @@ -714,7 +713,7 @@ func TestSugarBatchQuery(t *testing.T) { require.NoError(t, err) var account Account - err = pgxscan.ScanOne(&account, rows) + err = DB.Query.Scan.ScanOne(&account, rows) require.NoError(t, err) accounts = append(accounts, &account) } @@ -733,7 +732,7 @@ func TestSugarBatchQuery(t *testing.T) { // for _, rows := range batchRows { // var account Account - // err := pgxscan.ScanOne(&account, rows) + // err := DB.Query.Scan.ScanOne(&account, rows) // require.NoError(t, err) // accounts = append(accounts, &account) // }