From bb3d3a6f8e7a765ae7bda415505ab555905e1ca1 Mon Sep 17 00:00:00 2001 From: Vasily Tsybenko Date: Tue, 8 Oct 2024 22:49:37 +0300 Subject: [PATCH] Rename root package: db -> dbkit --- README.md | 2 +- config.go | 2 +- config_test.go | 2 +- constants.go | 2 +- db.go | 2 +- db_test.go | 2 +- dbrutil/dbrutil.go | 6 +-- dbrutil/dbrutil_test.go | 14 +++--- dbrutil/metric.go | 8 ++-- dbrutil/retry_test.go | 8 ++-- distrlock/db_lock.go | 16 +++---- distrlock/db_lock_test.go | 91 ++++++++++++++++++------------------ doc.go | 4 +- dsn.go | 2 +- dsn_test.go | 2 +- goquutil/goqutil_test.go | 8 ++-- goquutil/query.go | 2 +- internal/testing/deadlock.go | 10 ++-- metrics.go | 2 +- migrate/migrations.go | 14 +++--- migrate/migrations_test.go | 10 ++-- mssql/mssql.go | 2 +- mssql/mssql_test.go | 2 +- mysql/mysql.go | 2 +- mysql/mysql_test.go | 6 +-- pgx/deadlock_test.go | 4 +- pgx/postgres.go | 12 ++--- pgx/postgres_test.go | 26 +++++------ postgres/deadlock_test.go | 4 +- postgres/postgres.go | 10 ++-- postgres/postgres_test.go | 14 +++--- retryable.go | 2 +- retryable_test.go | 2 +- sqlite/sqlite.go | 2 +- sqlite/sqlite_test.go | 22 ++++----- 35 files changed, 159 insertions(+), 160 deletions(-) diff --git a/README.md b/README.md index 9079349..194bc9c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Structure ### `/` -Package `db` provides helpers for working with different SQL databases (MySQL, PostgreSQL, SQLite and MSSQL). +Package `dbkit` provides helpers for working with different SQL databases (MySQL, PostgreSQL, SQLite and MSSQL). ### `/distrlock` Package distrlock contains DML (distributed lock manager) implementation (now DMLs based on MySQL and PostgreSQL are supported). diff --git a/config.go b/config.go index efce0b8..b589fb0 100644 --- a/config.go +++ b/config.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "database/sql" diff --git a/config_test.go b/config_test.go index f14d943..3d76833 100644 --- a/config_test.go +++ b/config_test.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "bytes" diff --git a/constants.go b/constants.go index 16363a9..e2269d8 100644 --- a/constants.go +++ b/constants.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "database/sql" diff --git a/db.go b/db.go index 2da5c63..fec8603 100644 --- a/db.go +++ b/db.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "context" diff --git a/db_test.go b/db_test.go index b555d0f..382aaf0 100644 --- a/db_test.go +++ b/db_test.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "context" diff --git a/dbrutil/dbrutil.go b/dbrutil/dbrutil.go index 615b497..d28e360 100644 --- a/dbrutil/dbrutil.go +++ b/dbrutil/dbrutil.go @@ -25,14 +25,14 @@ import ( // Open opens database (using dbr query builder) with specified configuration parameters // and verifies (if ping argument is true) that connection can be established. -func Open(cfg *db.Config, ping bool, eventReceiver dbr.EventReceiver) (*dbr.Connection, error) { +func Open(cfg *dbkit.Config, ping bool, eventReceiver dbr.EventReceiver) (*dbr.Connection, error) { driver, dsn := cfg.DriverNameAndDSN() conn, err := dbr.Open(driver, dsn, eventReceiver) if err != nil { return nil, err } - if err := db.InitOpenedDB(conn.DB, cfg, ping); err != nil { + if err := dbkit.InitOpenedDB(conn.DB, cfg, ping); err != nil { return nil, err } @@ -183,7 +183,7 @@ func (s *RetryableTxSession) DoInTx(ctx context.Context, fn func(runner dbr.Sess _ = s.log.EventErrKv("backoff", err, map[string]string{"duration_ms": strconv.Itoa(int(d.Milliseconds()))}) } } - return retry.DoWithRetry(ctx, s.policy, db.GetIsRetryable(s.Driver()), notify, func(ctx context.Context) error { + return retry.DoWithRetry(ctx, s.policy, dbkit.GetIsRetryable(s.Driver()), notify, func(ctx context.Context) error { return s.TxSession.DoInTx(ctx, fn) }) } diff --git a/dbrutil/dbrutil_test.go b/dbrutil/dbrutil_test.go index 83ec059..ed763a5 100644 --- a/dbrutil/dbrutil_test.go +++ b/dbrutil/dbrutil_test.go @@ -32,9 +32,9 @@ INSERT INTO users(name) VALUES("Albert"), ("Bob"), ("John"), ("Sam"), ("Sam"); func openAndSeedDB(t *testing.T) *dbr.Connection { t.Helper() - cfg := &db.Config{ - Dialect: db.DialectSQLite, - SQLite: db.SQLiteConfig{Path: "file::memory:?cache=shared"}, + cfg := &dbkit.Config{ + Dialect: dbkit.DialectSQLite, + SQLite: dbkit.SQLiteConfig{Path: "file::memory:?cache=shared"}, MaxOpenConns: 1, MaxIdleConns: 1, ConnMaxLifetime: 0, @@ -146,25 +146,25 @@ func TestDbrQueryMetricsEventReceiver_TimingKv(t *testing.T) { }() t.Run("metrics for query with wrong annotation are not collected", func(t *testing.T) { - mc := db.NewMetricsCollector() + mc := dbkit.NewMetricsCollector() metricsEventReceiver := NewQueryMetricsEventReceiver(mc, "query_") dbSess := dbConn.NewSession(metricsEventReceiver) countUsersByName(t, dbSess, "count_users_by_name", "Sam", 2) - labels := prometheus.Labels{db.MetricsLabelQuery: "count_users_by_name"} + labels := prometheus.Labels{dbkit.MetricsLabelQuery: "count_users_by_name"} hist := mc.QueryDurations.With(labels).(prometheus.Histogram) testutil.RequireSamplesCountInHistogram(t, hist, 0) }) t.Run("metrics for query are collected", func(t *testing.T) { - mc := db.NewMetricsCollector() + mc := dbkit.NewMetricsCollector() metricsEventReceiver := NewQueryMetricsEventReceiver(mc, "query_") dbSess := dbConn.NewSession(metricsEventReceiver) countUsersByName(t, dbSess, "query_count_users_by_name", "Sam", 2) - labels := prometheus.Labels{db.MetricsLabelQuery: "query_count_users_by_name"} + labels := prometheus.Labels{dbkit.MetricsLabelQuery: "query_count_users_by_name"} hist := mc.QueryDurations.With(labels).(prometheus.Histogram) testutil.RequireSamplesCountInHistogram(t, hist, 1) }) diff --git a/dbrutil/metric.go b/dbrutil/metric.go index 8a5b896..669d6a3 100644 --- a/dbrutil/metric.go +++ b/dbrutil/metric.go @@ -25,13 +25,13 @@ type QueryMetricsEventReceiverOpts struct { // To be collected SQL query should be annotated (comment starting with specified prefix). type QueryMetricsEventReceiver struct { *dbr.NullEventReceiver - metricsCollector *db.MetricsCollector + metricsCollector *dbkit.MetricsCollector annotationPrefix string annotationModifier func(string) string } // NewQueryMetricsEventReceiverWithOpts creates a new QueryMetricsEventReceiver with additinal options. -func NewQueryMetricsEventReceiverWithOpts(mc *db.MetricsCollector, options QueryMetricsEventReceiverOpts) *QueryMetricsEventReceiver { +func NewQueryMetricsEventReceiverWithOpts(mc *dbkit.MetricsCollector, options QueryMetricsEventReceiverOpts) *QueryMetricsEventReceiver { return &QueryMetricsEventReceiver{ metricsCollector: mc, annotationPrefix: options.AnnotationPrefix, @@ -40,7 +40,7 @@ func NewQueryMetricsEventReceiverWithOpts(mc *db.MetricsCollector, options Query } // NewQueryMetricsEventReceiver creates a new QueryMetricsEventReceiver. -func NewQueryMetricsEventReceiver(mc *db.MetricsCollector, annotationPrefix string) *QueryMetricsEventReceiver { +func NewQueryMetricsEventReceiver(mc *dbkit.MetricsCollector, annotationPrefix string) *QueryMetricsEventReceiver { options := QueryMetricsEventReceiverOpts{ AnnotationPrefix: annotationPrefix, } @@ -54,6 +54,6 @@ func (er *QueryMetricsEventReceiver) TimingKv(eventName string, nanoseconds int6 if annotation == "" { return } - labels := prometheus.Labels{db.MetricsLabelQuery: annotation} + labels := prometheus.Labels{dbkit.MetricsLabelQuery: annotation} er.metricsCollector.QueryDurations.With(labels).Observe(time.Duration(nanoseconds).Seconds()) } diff --git a/dbrutil/retry_test.go b/dbrutil/retry_test.go index 7312030..48cc364 100644 --- a/dbrutil/retry_test.go +++ b/dbrutil/retry_test.go @@ -21,9 +21,9 @@ import ( // Test that retriable errors stays retriable even wrapped in Tx structures func TestTxErrorsIsRetriable(t *testing.T) { - retriable := []db.PostgresErrCode{ - db.PgxErrCodeDeadlockDetected, - db.PgxErrCodeSerializationFailure, + retriable := []dbkit.PostgresErrCode{ + dbkit.PgxErrCodeDeadlockDetected, + dbkit.PgxErrCodeSerializationFailure, } mkerr := func(code string) []error { @@ -34,7 +34,7 @@ func TestTxErrorsIsRetriable(t *testing.T) { } } - check := db.GetIsRetryable(&pg.Driver{}) + check := dbkit.GetIsRetryable(&pg.Driver{}) for _, c := range retriable { for _, err := range mkerr(string(c)) { diff --git a/distrlock/db_lock.go b/distrlock/db_lock.go index 6388945..6ea61ff 100644 --- a/distrlock/db_lock.go +++ b/distrlock/db_lock.go @@ -33,12 +33,12 @@ type DBManagerOpts struct { } // NewDBManager creates new distributed lock manager that uses SQL database as a backend. -func NewDBManager(dialect db.Dialect) (*DBManager, error) { +func NewDBManager(dialect dbkit.Dialect) (*DBManager, error) { return NewDBManagerWithOpts(dialect, DBManagerOpts{TableName: defaultTableName}) } // NewDBManagerWithOpts is a more configurable version of the NewDBManager. -func NewDBManagerWithOpts(dialect db.Dialect, opts DBManagerOpts) (*DBManager, error) { +func NewDBManagerWithOpts(dialect dbkit.Dialect, opts DBManagerOpts) (*DBManager, error) { q, err := newDBQueries(dialect, opts.TableName) if err != nil { return nil, err @@ -136,7 +136,7 @@ func (l *DBLock) DoExclusively( logger log.FieldLogger, fn func(ctx context.Context) error, ) error { - if acquireLockErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + if acquireLockErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return l.Acquire(ctx, tx, lockTTL) }); acquireLockErr != nil { return acquireLockErr @@ -148,7 +148,7 @@ func (l *DBLock) DoExclusively( // If the ctx is canceled, we should be able to release the lock. releaseCtx, releaseCtxCancel := context.WithTimeout(context.Background(), releaseTimeout) defer releaseCtxCancel() - if releaseLockErr := db.DoInTx(releaseCtx, dbConn, func(tx *sql.Tx) error { + if releaseLockErr := dbkit.DoInTx(releaseCtx, dbConn, func(tx *sql.Tx) error { return l.Release(releaseCtx, tx) }); releaseLockErr != nil { logger.Error("failed to release db lock", log.Error(releaseLockErr)) @@ -172,7 +172,7 @@ func (l *DBLock) DoExclusively( case <-periodicalExtensionDone: return case <-ticker.C: - if extendLockErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + if extendLockErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return l.Extend(ctx, tx) }); extendLockErr != nil { logger.Error("failed to extend db lock", log.Error(extendLockErr)) @@ -223,9 +223,9 @@ type dbQueries struct { intervalMaker func(interval time.Duration) string } -func newDBQueries(dialect db.Dialect, tableName string) (dbQueries, error) { +func newDBQueries(dialect dbkit.Dialect, tableName string) (dbQueries, error) { switch dialect { - case db.DialectPostgres, db.DialectPgx: + case dbkit.DialectPostgres, dbkit.DialectPgx: return dbQueries{ createTable: fmt.Sprintf(postgresCreateTableQuery, tableName), dropTable: fmt.Sprintf(postgresDropTableQuery, tableName), @@ -235,7 +235,7 @@ func newDBQueries(dialect db.Dialect, tableName string) (dbQueries, error) { extendLock: fmt.Sprintf(postgresExtendLockQuery, tableName), intervalMaker: postgresMakeInterval, }, nil - case db.DialectMySQL: + case dbkit.DialectMySQL: return dbQueries{ createTable: fmt.Sprintf(mySQLCreateTableQuery, tableName), dropTable: fmt.Sprintf(mySQLDropTableQuery, tableName), diff --git a/distrlock/db_lock_test.go b/distrlock/db_lock_test.go index 8352c52..d5e5e0c 100644 --- a/distrlock/db_lock_test.go +++ b/distrlock/db_lock_test.go @@ -32,27 +32,27 @@ import ( ) func TestDBManager_Postgres(t *gotesting.T) { - runDBManagerTests(t, db.DialectPostgres) + runDBManagerTests(t, dbkit.DialectPostgres) } func TestDBManager_Pgx(t *gotesting.T) { - runDBManagerTests(t, db.DialectPgx) + runDBManagerTests(t, dbkit.DialectPgx) } func TestDBManager_MySQL(t *gotesting.T) { - runDBManagerTests(t, db.DialectMySQL) + runDBManagerTests(t, dbkit.DialectMySQL) } func TestDBLock_DoExclusively_Postgres(t *gotesting.T) { - runDBLockDoExclusivelyTests(t, db.DialectPostgres) + runDBLockDoExclusivelyTests(t, dbkit.DialectPostgres) } func TestDBLock_DoExclusively_MySQL(t *gotesting.T) { - runDBLockDoExclusivelyTests(t, db.DialectMySQL) + runDBLockDoExclusivelyTests(t, dbkit.DialectMySQL) } //nolint:gocyclo -func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { +func runDBManagerTests(t *gotesting.T, dialect dbkit.Dialect) { containerCtx, containerCtxClose := context.WithTimeout(context.Background(), time.Minute*2) defer containerCtxClose() @@ -107,13 +107,13 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { require.Error(t, acquireErr) require.Empty(t, lock2.Token()) switch dialect { - case db.DialectMySQL: + case dbkit.DialectMySQL: require.ErrorIs(t, acquireErr, context.DeadlineExceeded) - case db.DialectPostgres: - // In Postgres case "canceling statement due to user request" error will be returned + case dbkit.DialectPostgres: + // In the Postgres' case "canceling statement due to user request" error will be returned // instead of context.DeadlineExceeded (pq "feature"). require.ErrorContains(t, acquireErr, "canceling statement due to user request") - case db.DialectPgx: + case dbkit.DialectPgx: require.ErrorIs(t, acquireErr, context.DeadlineExceeded) } }) @@ -157,16 +157,16 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { defer ctxCancel() var lock DBLock - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock, err = dbManager.NewLock(ctx, tx, lockKey) return err })) - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Acquire(ctx, tx, lockTimeout) })) - acquireErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + acquireErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Acquire(ctx, tx, lockTimeout) }) require.Error(t, acquireErr) @@ -182,29 +182,29 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { defer ctxCancel() var lock DBLock - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock, err = dbManager.NewLock(ctx, tx, lockKey) return err })) - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Acquire(ctx, tx, lockTimeout) })) // It must be impossible to acquire not released lock twice. - acquireErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + acquireErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Acquire(ctx, tx, lockTimeout) }) require.Error(t, acquireErr) require.ErrorIs(t, acquireErr, ErrLockAlreadyAcquired) // However after unlock ... - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Release(ctx, tx) })) // ... it must be possible to acquire the same lock at the second time. - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Acquire(ctx, tx, lockTimeout) })) }) @@ -220,7 +220,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { locks := make([]DBLock, locksNum) for i := 0; i < locksNum; i++ { - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { locks[i], err = dbManager.NewLock(ctx, tx, lockKey) //nolint:scopelint return err })) @@ -232,7 +232,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { wg.Add(1) go func(lock DBLock) { defer wg.Done() - errs <- db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + errs <- dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Acquire(ctx, tx, lockTimeout) }) }(locks[i]) @@ -262,7 +262,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { locks := make([]DBLock, locksNum) for i := 0; i < locksNum; i++ { - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { locks[i], err = dbManager.NewLock(ctx, tx, lockKey) //nolint:scopelint return err })) @@ -277,7 +277,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { defer wg.Done() // Continuously trying to acquire the lock. for { - acquireErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + acquireErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Acquire(ctx, tx, lockTimeout) }) if acquireErr == nil { @@ -298,7 +298,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { } // Release as soon as we got it locked. - releaseErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + releaseErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Release(ctx, tx) }) if releaseErr != nil { @@ -324,7 +324,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { defer ctxCancel() var lock DBLock - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock, err = dbManager.NewLock(ctx, tx, lockKey) if err != nil { return @@ -335,7 +335,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { // wait for a timeout time.Sleep(lockTimeout * 2) - releaseErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + releaseErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Release(ctx, tx) }) require.ErrorIs(t, releaseErr, ErrLockAlreadyReleased) @@ -351,7 +351,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { defer ctxCancel() var lock DBLock - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock, err = dbManager.NewLock(ctx, tx, lockKey) if err != nil { return @@ -360,7 +360,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { })) // must be able to acquire the lock with the same token - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock, err = dbManager.NewLock(ctx, tx, lockKey) if err != nil { return @@ -368,11 +368,11 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { return lock.AcquireWithStaticToken(ctx, tx, token, lockTTL) })) - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Release(ctx, tx) })) - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock, err = dbManager.NewLock(ctx, tx, lockKey) if err != nil { return @@ -380,7 +380,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { return lock.Acquire(ctx, tx, lockTTL) })) - acquireErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + acquireErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.AcquireWithStaticToken(ctx, tx, token, lockTTL) }) require.ErrorIs(t, acquireErr, ErrLockAlreadyAcquired, "it must be impossible to acquire already acquired lock with different token") @@ -411,14 +411,13 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { acquireErr := lock2.Acquire(ctx, tx2, lockTimeout) require.Error(t, acquireErr) - if dialect != db.DialectPostgres { + if dialect != dbkit.DialectPostgres { require.ErrorIs(t, acquireErr, context.DeadlineExceeded) } else { - if ctx.Err() == nil { - require.ErrorContains(t, acquireErr, "canceling statement due to user request") - } else { - require.ErrorIs(t, acquireErr, context.DeadlineExceeded) - } + require.Truef(t, + strings.Contains(acquireErr.Error(), "canceling statement due to user request") || + errors.Is(acquireErr, context.DeadlineExceeded), + "unexpected error: %v", acquireErr) } require.Empty(t, lock2.Token()) }, @@ -433,7 +432,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { defer ctxCancel() var lock DBLock - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock, err = dbManager.NewLock(ctx, tx, lockKey) if err != nil { return @@ -444,7 +443,7 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { // Extend lock 3 times. for i := 0; i < 3; i++ { time.Sleep(lockTimeout / 2) - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Extend(ctx, tx) })) } @@ -452,14 +451,14 @@ func runDBManagerTests(t *gotesting.T, dialect db.Dialect) { // Wait while lock will be released by timeout. time.Sleep(lockTimeout * 2) - extendErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + extendErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { return lock.Extend(ctx, tx) }) require.ErrorIs(t, extendErr, ErrLockAlreadyReleased) }) } -func runDBLockDoExclusivelyTests(t *gotesting.T, dialect db.Dialect) { +func runDBLockDoExclusivelyTests(t *gotesting.T, dialect dbkit.Dialect) { containerCtx, containerCtxClose := context.WithTimeout(context.Background(), time.Minute*2) defer containerCtxClose() @@ -555,13 +554,13 @@ func makeTwoLocks( ) (lock1, lock2 DBLock) { t.Helper() - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock1, err = dbManager.NewLock(ctx, tx, key1) return err })) require.Equal(t, key1, lock1.Key) - require.NoError(t, db.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { + require.NoError(t, dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) (err error) { lock2, err = dbManager.NewLock(ctx, tx, key2) return err })) @@ -570,21 +569,21 @@ func makeTwoLocks( return } -func assertRollbackWithCtxTimeoutError(t *gotesting.T, dialect db.Dialect, tx *sql.Tx) func() { +func assertRollbackWithCtxTimeoutError(t *gotesting.T, dialect dbkit.Dialect, tx *sql.Tx) func() { return func() { rollbackErr := tx.Rollback() var ok bool switch dialect { - case db.DialectMySQL: + case dbkit.DialectMySQL: ok = assert.True(t, errors.Is(rollbackErr, sql.ErrTxDone) || errors.Is(rollbackErr, mysql.ErrInvalidConn) || rollbackErr == nil, // Rollback sometimes can return nil error in case of mysql driver . ) - case db.DialectPostgres: + case dbkit.DialectPostgres: ok = assert.True(t, errors.Is(rollbackErr, sql.ErrTxDone) || errors.Is(rollbackErr, driver.ErrBadConn) || strings.Contains(rollbackErr.Error(), "canceling statement due to user request")) - case db.DialectPgx: + case dbkit.DialectPgx: ok = assert.True(t, errors.Is(rollbackErr, sql.ErrTxDone) || errors.Is(rollbackErr, context.DeadlineExceeded) || strings.Contains(rollbackErr.Error(), "conn closed"), // Pgx may return `conn closed` error when context timeout exceeded. diff --git a/doc.go b/doc.go index 4e934d9..b0bb743 100644 --- a/doc.go +++ b/doc.go @@ -4,5 +4,5 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -// Package db provides helpers for working with different SQL databases (MySQL, PostgreSQL, SQLite and MSSQL). -package db +// Package dbkit provides helpers for working with different SQL databases (MySQL, PostgreSQL, SQLite, and MSSQL). +package dbkit diff --git a/dsn.go b/dsn.go index d06d083..db3eb5b 100644 --- a/dsn.go +++ b/dsn.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "fmt" diff --git a/dsn_test.go b/dsn_test.go index 1652f22..9321482 100644 --- a/dsn_test.go +++ b/dsn_test.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "database/sql" diff --git a/goquutil/goqutil_test.go b/goquutil/goqutil_test.go index 6a14d1e..610182f 100644 --- a/goquutil/goqutil_test.go +++ b/goquutil/goqutil_test.go @@ -58,9 +58,9 @@ type ItemWithUser struct { func openAndSeedDB(t *testing.T) *DB { t.Helper() - cfg := &db.Config{ - Dialect: db.DialectSQLite, - SQLite: db.SQLiteConfig{Path: "file::memory:?cache=shared"}, + cfg := &dbkit.Config{ + Dialect: dbkit.DialectSQLite, + SQLite: dbkit.SQLiteConfig{Path: "file::memory:?cache=shared"}, MaxOpenConns: 1, MaxIdleConns: 1, ConnMaxLifetime: 0, @@ -68,7 +68,7 @@ func openAndSeedDB(t *testing.T) *DB { dbConn, err := sql.Open("sqlite3", ":memory:") require.NoError(t, err) - require.NoError(t, db.InitOpenedDB(dbConn, cfg, false)) + require.NoError(t, dbkit.InitOpenedDB(dbConn, cfg, false)) _, err = dbConn.Exec(sqlCreateAndSeedTestUsersTable) require.NoError(t, err) diff --git a/goquutil/query.go b/goquutil/query.go index 7884c27..25b2e8d 100644 --- a/goquutil/query.go +++ b/goquutil/query.go @@ -213,7 +213,7 @@ func prepareSelectsForCompositeRecord(query *goqu.SelectDataset, structTyp inter return cols[i].col < cols[j].col }) - dialectSqlite := query.Dialect().Dialect() == string(db.DialectSQLite) + dialectSqlite := query.Dialect().Dialect() == string(dbkit.DialectSQLite) for i := range cols { col, defaultV := cols[i].col, cols[i].defaultV var selectExp exp.Expression diff --git a/internal/testing/deadlock.go b/internal/testing/deadlock.go index c652ffe..943dd25 100644 --- a/internal/testing/deadlock.go +++ b/internal/testing/deadlock.go @@ -19,7 +19,7 @@ import ( ) // DeadlockTest is internal function to simulate DB deadlock -func DeadlockTest(t *testing.T, dialect db.Dialect, checkDeadlockErr func(err error) bool) { +func DeadlockTest(t *testing.T, dialect dbkit.Dialect, checkDeadlockErr func(err error) bool) { ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*30) defer ctxCancel() dbConn, stop := MustRunAndOpenTestDB(ctx, string(dialect)) @@ -50,7 +50,7 @@ func DeadlockTest(t *testing.T, dialect db.Dialect, checkDeadlockErr func(err er go func(ctx context.Context) { defer done.Done() - tx1Err = db.DoInTxWithOpts(ctx, dbConn, txOpts, func(tx *sql.Tx) error { + tx1Err = dbkit.DoInTxWithOpts(ctx, dbConn, txOpts, func(tx *sql.Tx) error { if _, err := tx.Exec(fmt.Sprintf("UPDATE %s SET name=$1 WHERE id=$2", table1Name), "test100", 1); err != nil { return err } @@ -66,7 +66,7 @@ func DeadlockTest(t *testing.T, dialect db.Dialect, checkDeadlockErr func(err er done.Add(1) go func(ctx context.Context) { defer done.Done() - tx2Err = db.DoInTxWithOpts(ctx, dbConn, txOpts, func(tx *sql.Tx) error { + tx2Err = dbkit.DoInTxWithOpts(ctx, dbConn, txOpts, func(tx *sql.Tx) error { if _, err := tx.Exec(fmt.Sprintf("UPDATE %s SET name=$1 WHERE id=$2", table2Name), "test100", 1); err != nil { return err } @@ -96,7 +96,7 @@ func DeadlockTest(t *testing.T, dialect db.Dialect, checkDeadlockErr func(err er } func cleanupDB(ctx context.Context, dbConn *sql.DB, table1Name string, table2Name string) error { - return db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + return dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { if _, err := tx.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s;", table1Name)); err != nil { return err } @@ -108,7 +108,7 @@ func cleanupDB(ctx context.Context, dbConn *sql.DB, table1Name string, table2Nam } func createTables(ctx context.Context, dbConn *sql.DB, table2Name string, table1Name string) error { - tErr := db.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { + tErr := dbkit.DoInTx(ctx, dbConn, func(tx *sql.Tx) error { _, err := tx.Exec(fmt.Sprintf("CREATE TABLE %s (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL);", table2Name)) if err != nil { return err diff --git a/metrics.go b/metrics.go index d49b2c7..dba8c0d 100644 --- a/metrics.go +++ b/metrics.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import "github.com/prometheus/client_golang/prometheus" diff --git a/migrate/migrations.go b/migrate/migrations.go index 89f5710..8466951 100644 --- a/migrate/migrations.go +++ b/migrate/migrations.go @@ -58,7 +58,7 @@ type TxDisabler interface { // NullMigration represents an empty basic migration that may be embedded in regular migrations // in order to write less code for satisfying the Migration interface. type NullMigration struct { - Dialect db.Dialect + Dialect dbkit.Dialect } // ID is a stub that returns empty migration identifier. @@ -128,7 +128,7 @@ func (m *CustomMigration) DownFn() func(tx *sql.Tx) error { // MigrationsManager is an object for running migrations. type MigrationsManager struct { db *sql.DB - Dialect db.Dialect + Dialect dbkit.Dialect migSet migrate.MigrationSet logger log.FieldLogger } @@ -139,7 +139,7 @@ type MigrationsManagerOpts struct { } // NewMigrationsManager creates a new MigrationsManager. -func NewMigrationsManager(dbConn *sql.DB, dialect db.Dialect, logger log.FieldLogger) (*MigrationsManager, error) { +func NewMigrationsManager(dbConn *sql.DB, dialect dbkit.Dialect, logger log.FieldLogger) (*MigrationsManager, error) { migSet := migrate.MigrationSet{TableName: MigrationsTableName} return &MigrationsManager{dbConn, normalizeDialect(dialect), migSet, logger}, nil } @@ -147,7 +147,7 @@ func NewMigrationsManager(dbConn *sql.DB, dialect db.Dialect, logger log.FieldLo // NewMigrationsManagerWithOpts creates a new MigrationsManager with custom options func NewMigrationsManagerWithOpts( dbConn *sql.DB, - dialect db.Dialect, + dialect dbkit.Dialect, logger log.FieldLogger, opts MigrationsManagerOpts, ) (*MigrationsManager, error) { @@ -160,9 +160,9 @@ func NewMigrationsManagerWithOpts( } // TODO: normalizeDialect sets standard lib/pq driver for pgx dialect because pgx isn't supported by sql-migrate yet. -func normalizeDialect(dialect db.Dialect) db.Dialect { - if dialect == db.DialectPgx { - return db.DialectPostgres +func normalizeDialect(dialect dbkit.Dialect) dbkit.Dialect { + if dialect == dbkit.DialectPgx { + return dbkit.DialectPostgres } return dialect } diff --git a/migrate/migrations_test.go b/migrate/migrations_test.go index a5e0ed0..f805674 100644 --- a/migrate/migrations_test.go +++ b/migrate/migrations_test.go @@ -161,7 +161,7 @@ func TestMigrationsManager_Run(t *testing.T) { require.NoError(t, err) defer requireNoErrOnClose(t, dbConn) - migMngr, err := NewMigrationsManager(dbConn, db.DialectSQLite, logtest.NewLogger()) + migMngr, err := NewMigrationsManager(dbConn, dbkit.DialectSQLite, logtest.NewLogger()) require.NoError(t, err) migrations := []Migration{newTestMigration00001CreateTables(), newTestMigration00002SeedTabled()} @@ -182,7 +182,7 @@ func TestMigrationsManager_RunLimit(t *testing.T) { require.NoError(t, err) defer requireNoErrOnClose(t, dbConn) - migMngr, err := NewMigrationsManager(dbConn, db.DialectSQLite, logtest.NewLogger()) + migMngr, err := NewMigrationsManager(dbConn, dbkit.DialectSQLite, logtest.NewLogger()) require.NoError(t, err) migrations := []Migration{newTestMigration00001CreateTables(), newTestMigration00002SeedTabled()} @@ -207,7 +207,7 @@ func TestMigrationsManager_Status(t *testing.T) { require.NoError(t, err) defer requireNoErrOnClose(t, dbConn) - migMngr, err := NewMigrationsManager(dbConn, db.DialectSQLite, logtest.NewLogger()) + migMngr, err := NewMigrationsManager(dbConn, dbkit.DialectSQLite, logtest.NewLogger()) require.NoError(t, err) migStatus, err := migMngr.Status() @@ -236,7 +236,7 @@ func TestCreationMigrationManagerWithOpts(t *testing.T) { migMngr, err := NewMigrationsManagerWithOpts( dbConn, - db.DialectSQLite, + dbkit.DialectSQLite, logtest.NewLogger(), MigrationsManagerOpts{TableName: tableName}, ) @@ -271,7 +271,7 @@ func TestMigrationsManager_supportRawMigration(t *testing.T) { require.NoError(t, err) defer requireNoErrOnClose(t, dbConn) - migMngr, err := NewMigrationsManager(dbConn, db.DialectSQLite, logtest.NewLogger()) + migMngr, err := NewMigrationsManager(dbConn, dbkit.DialectSQLite, logtest.NewLogger()) require.NoError(t, err) migrations := []Migration{ newTestMigration00001CreateTables(), diff --git a/mssql/mssql.go b/mssql/mssql.go index 8a53698..18fdebf 100644 --- a/mssql/mssql.go +++ b/mssql/mssql.go @@ -19,7 +19,7 @@ import ( // nolint func init() { - db.RegisterIsRetryableFunc(&mssql.Driver{}, func(err error) bool { + dbkit.RegisterIsRetryableFunc(&mssql.Driver{}, func(err error) bool { if msErr, ok := err.(mssql.Error); ok { if msErr.Number == int32(MSSQLErrDeadlock) { // deadlock error return true diff --git a/mssql/mssql_test.go b/mssql/mssql_test.go index 6f91689..8836b5c 100644 --- a/mssql/mssql_test.go +++ b/mssql/mssql_test.go @@ -18,7 +18,7 @@ import ( ) func TestMSSQLIsRetryable(t *testing.T) { - isRetryable := db.GetIsRetryable(&mssql.Driver{}) + isRetryable := dbkit.GetIsRetryable(&mssql.Driver{}) require.NotNil(t, isRetryable) require.True(t, isRetryable(mssql.Error{Number: 1205})) require.False(t, isRetryable(driver.ErrBadConn)) diff --git a/mysql/mysql.go b/mysql/mysql.go index 0014c40..914e89a 100644 --- a/mysql/mysql.go +++ b/mysql/mysql.go @@ -21,7 +21,7 @@ import ( // nolint func init() { - db.RegisterIsRetryableFunc(&mysql.MySQLDriver{}, func(err error) bool { + dbkit.RegisterIsRetryableFunc(&mysql.MySQLDriver{}, func(err error) bool { if mysqlErr, ok := err.(*mysql.MySQLError); ok { switch mysqlErr.Number { case uint16(MySQLErrDeadlock), uint16(MySQLErrLockTimedOut): diff --git a/mysql/mysql_test.go b/mysql/mysql_test.go index 2947be5..3c64654 100644 --- a/mysql/mysql_test.go +++ b/mysql/mysql_test.go @@ -18,7 +18,7 @@ import ( ) func TestMakeMySQLDSN(t *testing.T) { - cfg := &db.MySQLConfig{ + cfg := &dbkit.MySQLConfig{ Host: "myhost", Port: 3307, User: "myadmin", @@ -26,12 +26,12 @@ func TestMakeMySQLDSN(t *testing.T) { Database: "mydb", } wantDSN := "myadmin:mypassword@tcp(myhost:3307)/mydb?multiStatements=true&parseTime=true&autocommit=false" - gotDSN := db.MakeMySQLDSN(cfg) + gotDSN := dbkit.MakeMySQLDSN(cfg) require.Equal(t, wantDSN, gotDSN) } func TestMysqlIsRetryable(t *testing.T) { - isRetryable := db.GetIsRetryable(&mysql.MySQLDriver{}) + isRetryable := dbkit.GetIsRetryable(&mysql.MySQLDriver{}) require.NotNil(t, isRetryable) require.True(t, isRetryable(&mysql.MySQLError{ Number: uint16(MySQLErrDeadlock), diff --git a/pgx/deadlock_test.go b/pgx/deadlock_test.go index 12a36d6..81da2a4 100644 --- a/pgx/deadlock_test.go +++ b/pgx/deadlock_test.go @@ -14,8 +14,8 @@ import ( ) func TestDeadlockErrorHandling(t *gotesting.T) { - testing.DeadlockTest(t, db.DialectPgx, + testing.DeadlockTest(t, dbkit.DialectPgx, func(err error) bool { - return CheckPostgresError(err, db.PgxErrCodeDeadlockDetected) + return CheckPostgresError(err, dbkit.PgxErrCodeDeadlockDetected) }) } diff --git a/pgx/postgres.go b/pgx/postgres.go index 3cdd67d..3231213 100644 --- a/pgx/postgres.go +++ b/pgx/postgres.go @@ -20,12 +20,12 @@ import ( // nolint func init() { - db.RegisterIsRetryableFunc(&pg.Driver{}, func(err error) bool { + dbkit.RegisterIsRetryableFunc(&pg.Driver{}, func(err error) bool { if pgErr, ok := err.(*pgconn.PgError); ok { - switch errCode := db.PostgresErrCode(pgErr.Code); errCode { - case db.PgxErrCodeDeadlockDetected: + switch errCode := dbkit.PostgresErrCode(pgErr.Code); errCode { + case dbkit.PgxErrCodeDeadlockDetected: return true - case db.PgxErrCodeSerializationFailure: + case dbkit.PgxErrCodeSerializationFailure: return true } if checkInvalidCachedPlanPgError(pgErr) { @@ -38,7 +38,7 @@ func init() { // CheckPostgresError checks if the passed error relates to Postgres, // and it's internal code matches the one from the argument. -func CheckPostgresError(err error, errCode db.PostgresErrCode) bool { +func CheckPostgresError(err error, errCode dbkit.PostgresErrCode) bool { if pgErr, ok := err.(*pgconn.PgError); ok { return pgErr.Code == string(errCode) } @@ -63,6 +63,6 @@ func CheckInvalidCachedPlanError(err error) bool { // Source: https://github.com/jackc/pgconn/blob/9cf57526250f6cd3e6cbf4fd7269c882e66898ce/stmtcache/lru.go#L91-L103 func checkInvalidCachedPlanPgError(pgErr *pgconn.PgError) bool { return pgErr.Severity == "ERROR" && - pgErr.Code == string(db.PgxErrFeatureNotSupported) && + pgErr.Code == string(dbkit.PgxErrFeatureNotSupported) && pgErr.Message == "cached plan must not change result type" } diff --git a/pgx/postgres_test.go b/pgx/postgres_test.go index 4977060..4ced76a 100644 --- a/pgx/postgres_test.go +++ b/pgx/postgres_test.go @@ -24,33 +24,33 @@ import ( func TestMakePostgresDSN(t *gotesting.T) { tests := []struct { Name string - Cfg *db.PostgresConfig + Cfg *dbkit.PostgresConfig WantDSN string }{ { Name: "search_path is used", - Cfg: &db.PostgresConfig{ + Cfg: &dbkit.PostgresConfig{ Host: "pghost", Port: 5433, User: "pgadmin", Password: "pgpassword", Database: "pgdb", - SSLMode: db.PostgresSSLModeRequire, + SSLMode: dbkit.PostgresSSLModeRequire, SearchPath: "pgsearch", - AdditionalParameters: []db.Parameter{{"param1", "foo"}, {"param2", "bar"}}, + AdditionalParameters: []dbkit.Parameter{{"param1", "foo"}, {"param2", "bar"}}, }, WantDSN: "postgres://pgadmin:pgpassword@pghost:5433/pgdb?sslmode=require&search_path=pgsearch¶m1=foo¶m2=bar", }, { Name: "base", - Cfg: &db.PostgresConfig{ + Cfg: &dbkit.PostgresConfig{ Host: "pghost", Port: 5433, User: "pgadmin", Password: "pgpassword", Database: "pgdb", - SSLMode: db.PostgresSSLModeRequire, - AdditionalParameters: []db.Parameter{{"param1", "Lorem ipsum"}}, + SSLMode: dbkit.PostgresSSLModeRequire, + AdditionalParameters: []dbkit.Parameter{{"param1", "Lorem ipsum"}}, }, WantDSN: "postgres://pgadmin:pgpassword@pghost:5433/pgdb?sslmode=require¶m1=Lorem+ipsum", }, @@ -58,18 +58,18 @@ func TestMakePostgresDSN(t *gotesting.T) { for i := range tests { tt := tests[i] t.Run(tt.Name, func(t *gotesting.T) { - require.Equal(t, db.MakePostgresDSN(tt.Cfg), tt.WantDSN) + require.Equal(t, dbkit.MakePostgresDSN(tt.Cfg), tt.WantDSN) }) } } func TestPostgresIsRetryable(t *gotesting.T) { - isRetryable := db.GetIsRetryable(&pg.Driver{}) + isRetryable := dbkit.GetIsRetryable(&pg.Driver{}) require.NotNil(t, isRetryable) // enum all retriable errors - retriable := []db.PostgresErrCode{ - db.PgxErrCodeDeadlockDetected, - db.PgxErrCodeSerializationFailure, + retriable := []dbkit.PostgresErrCode{ + dbkit.PgxErrCodeDeadlockDetected, + dbkit.PgxErrCodeSerializationFailure, } for _, code := range retriable { var err error @@ -88,7 +88,7 @@ func TestCheckInvalidCachedPlanError(t *gotesting.T) { ctx, ctxCancel := context.WithTimeout(context.Background(), time.Minute*2) defer ctxCancel() - conn, stop := testing.MustRunAndOpenTestDB(ctx, string(db.DialectPgx)) + conn, stop := testing.MustRunAndOpenTestDB(ctx, string(dbkit.DialectPgx)) defer func() { require.NoError(t, stop(ctx)) }() // Create a table and fill it with some data. diff --git a/postgres/deadlock_test.go b/postgres/deadlock_test.go index 1cd39c3..1cee888 100644 --- a/postgres/deadlock_test.go +++ b/postgres/deadlock_test.go @@ -14,8 +14,8 @@ import ( ) func TestDeadlockErrorHandling(t *testing.T) { - testing2.DeadlockTest(t, db.DialectPostgres, + testing2.DeadlockTest(t, dbkit.DialectPostgres, func(err error) bool { - return CheckPostgresError(err, db.PostgresErrCodeDeadlockDetected) + return CheckPostgresError(err, dbkit.PostgresErrCodeDeadlockDetected) }) } diff --git a/postgres/postgres.go b/postgres/postgres.go index 3148eec..e9f3fd4 100644 --- a/postgres/postgres.go +++ b/postgres/postgres.go @@ -19,13 +19,13 @@ import ( // nolint func init() { - db.RegisterIsRetryableFunc(&pg.Driver{}, func(err error) bool { + dbkit.RegisterIsRetryableFunc(&pg.Driver{}, func(err error) bool { if pgErr, ok := err.(*pg.Error); ok { - name := db.PostgresErrCode(pgErr.Code.Name()) + name := dbkit.PostgresErrCode(pgErr.Code.Name()) switch name { - case db.PostgresErrCodeDeadlockDetected: + case dbkit.PostgresErrCodeDeadlockDetected: return true - case db.PostgresErrCodeSerializationFailure: + case dbkit.PostgresErrCodeSerializationFailure: return true } } @@ -35,7 +35,7 @@ func init() { // CheckPostgresError checks if the passed error relates to Postgres and it's internal code matches the one from the argument. // nolint: staticcheck // lib/pq using is deprecated. Use pgx Postgres driver. -func CheckPostgresError(err error, errCode db.PostgresErrCode) bool { +func CheckPostgresError(err error, errCode dbkit.PostgresErrCode) bool { if pgErr, ok := err.(*pg.Error); ok { return pgErr.Code.Name() == string(errCode) } diff --git a/postgres/postgres_test.go b/postgres/postgres_test.go index d3d29cd..724dfd7 100644 --- a/postgres/postgres_test.go +++ b/postgres/postgres_test.go @@ -20,31 +20,31 @@ import ( func TestMakePostgresDSN(t *testing.T) { tests := []struct { Name string - Cfg *db.PostgresConfig + Cfg *dbkit.PostgresConfig WantDSN string }{ { Name: "search_path is used", - Cfg: &db.PostgresConfig{ + Cfg: &dbkit.PostgresConfig{ Host: "pghost", Port: 5433, User: "pgadmin", Password: "pgpassword", Database: "pgdb", - SSLMode: db.PostgresSSLModeRequire, + SSLMode: dbkit.PostgresSSLModeRequire, SearchPath: "pgsearch", }, WantDSN: "postgres://pgadmin:pgpassword@pghost:5433/pgdb?sslmode=require&search_path=pgsearch", }, { Name: "base", - Cfg: &db.PostgresConfig{ + Cfg: &dbkit.PostgresConfig{ Host: "pghost", Port: 5433, User: "pgadmin", Password: "pgpassword", Database: "pgdb", - SSLMode: db.PostgresSSLModeRequire, + SSLMode: dbkit.PostgresSSLModeRequire, }, WantDSN: "postgres://pgadmin:pgpassword@pghost:5433/pgdb?sslmode=require", }, @@ -52,13 +52,13 @@ func TestMakePostgresDSN(t *testing.T) { for i := range tests { tt := tests[i] t.Run(tt.Name, func(t *testing.T) { - require.Equal(t, db.MakePostgresDSN(tt.Cfg), tt.WantDSN) + require.Equal(t, dbkit.MakePostgresDSN(tt.Cfg), tt.WantDSN) }) } } func TestPostgresIsRetryable(t *testing.T) { - isRetryable := db.GetIsRetryable(&pg.Driver{}) + isRetryable := dbkit.GetIsRetryable(&pg.Driver{}) require.NotNil(t, isRetryable) require.True(t, isRetryable(&pg.Error{Code: "40P01"})) require.False(t, isRetryable(driver.ErrBadConn)) diff --git a/retryable.go b/retryable.go index 84bb6c9..9337cc3 100644 --- a/retryable.go +++ b/retryable.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "database/sql/driver" diff --git a/retryable_test.go b/retryable_test.go index e0777d9..97fe28a 100644 --- a/retryable_test.go +++ b/retryable_test.go @@ -4,7 +4,7 @@ Copyright © 2024 Acronis International GmbH. Released under MIT license. */ -package db +package dbkit import ( "context" diff --git a/sqlite/sqlite.go b/sqlite/sqlite.go index 8ee0691..aa2a604 100644 --- a/sqlite/sqlite.go +++ b/sqlite/sqlite.go @@ -19,7 +19,7 @@ import ( // nolint func init() { - db.RegisterIsRetryableFunc(&sqlite3.SQLiteDriver{}, func(err error) bool { + dbkit.RegisterIsRetryableFunc(&sqlite3.SQLiteDriver{}, func(err error) bool { if sqliteErr, ok := err.(sqlite3.Error); ok { switch sqliteErr.Code { case sqlite3.ErrLocked, sqlite3.ErrBusy: diff --git a/sqlite/sqlite_test.go b/sqlite/sqlite_test.go index 4d6de80..671f561 100644 --- a/sqlite/sqlite_test.go +++ b/sqlite/sqlite_test.go @@ -51,7 +51,7 @@ func TestSqliteRetryOnBusyError(t *testing.T) { var attempts int var firstErr error backOffPolicy := retry.NewConstantBackoffPolicy(time.Millisecond*busyTimeoutMs/2, 10) - require.NoError(t, retry.DoWithRetry(context.Background(), backOffPolicy, db.GetIsRetryable(dbConn2.Driver()), nil, func(ctx context.Context) error { + require.NoError(t, retry.DoWithRetry(context.Background(), backOffPolicy, dbkit.GetIsRetryable(dbConn2.Driver()), nil, func(ctx context.Context) error { attempts++ execErr := execInTx(ctx, dbConn2, `insert into foo values (2, "two")`) if firstErr == nil { @@ -94,7 +94,7 @@ func TestSqliteRetryOnBusyErrorTimedOut(t *testing.T) { var attempts int var firstErr error backOffPolicy := retry.NewConstantBackoffPolicy(time.Millisecond*busyTimeoutMs/2, 10) - err = retry.DoWithRetry(ctx, backOffPolicy, db.GetIsRetryable(dbConn2.Driver()), nil, func(ctx context.Context) error { + err = retry.DoWithRetry(ctx, backOffPolicy, dbkit.GetIsRetryable(dbConn2.Driver()), nil, func(ctx context.Context) error { attempts++ execErr := execInTx(ctx, dbConn2, `insert into foo values (2, "two")`) if firstErr == nil { @@ -118,7 +118,7 @@ func TestNoRetryOnOtherErrors(t *testing.T) { var attempts int backOffPolicy := retry.NewConstantBackoffPolicy(time.Millisecond, 10) - err = retry.DoWithRetry(context.Background(), backOffPolicy, db.GetIsRetryable(dbConn.Driver()), nil, func(ctx context.Context) error { + err = retry.DoWithRetry(context.Background(), backOffPolicy, dbkit.GetIsRetryable(dbConn.Driver()), nil, func(ctx context.Context) error { attempts++ _, err = dbConn.Exec(`drop table foo`) return err @@ -128,7 +128,7 @@ func TestNoRetryOnOtherErrors(t *testing.T) { } func TestSqliteIsRetryable(t *testing.T) { - isRetryable := db.GetIsRetryable(&sqlite3.SQLiteDriver{}) + isRetryable := dbkit.GetIsRetryable(&sqlite3.SQLiteDriver{}) require.NotNil(t, isRetryable) require.True(t, isRetryable(sqlite3.Error{ Code: sqlite3.ErrBusy, @@ -173,11 +173,11 @@ func execInTx(ctx context.Context, dbConn *sql.DB, stmt string) error { func TestConfig(t *testing.T) { t.Run("read sqlite parameters", func(t *testing.T) { - allDialects := []db.Dialect{ - db.DialectSQLite, - db.DialectMySQL, - db.DialectPostgres, - db.DialectMSSQL, + allDialects := []dbkit.Dialect{ + dbkit.DialectSQLite, + dbkit.DialectMySQL, + dbkit.DialectPostgres, + dbkit.DialectMSSQL, } cfgData := bytes.NewBufferString(` @@ -189,13 +189,13 @@ db: sqlite3: path: ":memory:" `) - cfg := db.NewConfig(allDialects) + cfg := dbkit.NewConfig(allDialects) err := config.NewDefaultLoader("").LoadFromReader(cfgData, config.DataTypeYAML, cfg) require.NoError(t, err) require.Equal(t, 20, cfg.MaxOpenConns) require.Equal(t, 10, cfg.MaxIdleConns) require.Equal(t, time.Minute, cfg.ConnMaxLifetime) - require.Equal(t, db.DialectSQLite, cfg.Dialect) + require.Equal(t, dbkit.DialectSQLite, cfg.Dialect) require.Equal(t, ":memory:", cfg.SQLite.Path) require.Equal(t, sql.LevelDefault, cfg.TxIsolationLevel()) })