Skip to content

Commit

Permalink
Ignore error when new column is added to DB schema (allow backward-co…
Browse files Browse the repository at this point in the history
…mpatible migrations) (#15)

* Add extra column to test #13 backward-compatibility

#13

* Fix panic in test

* Ignore scany errors on unknown columns

Fixes this error:
scany: column: 'new_field': no corresponding field found, or it's unexported in data.Collection
  • Loading branch information
VojtechVitek authored Jun 3, 2024
1 parent 0d9f7d7 commit 8cb5235
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 18 deletions.
19 changes: 18 additions & 1 deletion pgkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down
9 changes: 5 additions & 4 deletions querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
type Querier struct {
pool *pgxpool.Pool
tx pgx.Tx
Scan *pgxscan.API
SQL *StatementBuilder
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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)
// // }
Expand All @@ -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)
// }
Expand Down
25 changes: 12 additions & 13 deletions tests/pgkit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -72,19 +71,19 @@ func TestInsertAndSelectRows(t *testing.T) {

// Insert
insertq, args, err := DB.SQL.Insert("accounts").Columns("name", "disabled").Values("peter", false).ToSql()
assert.NoError(t, err)
require.NoError(t, err)

_, err = DB.Conn.Exec(context.Background(), insertq, args...)
assert.NoError(t, err)
require.NoError(t, err)

// Select all
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...)

assert.NoError(t, err)
assert.Len(t, accounts, 1)
require.NoError(t, err)
require.Len(t, accounts, 1)
assert.True(t, accounts[0].ID != 0)
assert.Equal(t, "peter", accounts[0].Name)
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
Expand All @@ -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))
}
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
// }
Expand Down
1 change: 1 addition & 0 deletions tests/testdata/pgkit_test_db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
disabled BOOLEAN,
new_column_not_in_code BOOLEAN, -- test for backward-compatible migrations, see https://github.com/goware/pgkit/issues/13
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);

Expand Down

0 comments on commit 8cb5235

Please sign in to comment.