* feature (db): add Db.UnderlyingDB() This is needed to allow for integration with bits that need a *dbw.DB * feature (kms): add new go-kms-wrapping/extras/kms dependency * refactor (kms): schema changes required to adopt extras/kms pkg * refactor (kms/iam): rename to DeprecateCreateKeysTx(...) * refactor (kms): remove deprecated test * refactor (kms): refactor Kms type This refactor includes renaming the existing type to DeprecatedKms and then refactoring the Kms type to become a wrapper of go-kms-wrapping/extras/kms * refactor (kms): delete all the unneeded bits All this stuff is not needed now that we're using go-kms-wrapping/extras/kms * refactor (db): fixup tests after kms refactor * refactor (kms/tests): use testing.TB for test helpers Our test helper packages were not possible to use with benchmarks. This refactor switches to testing.TB to allow both tests and benchmarks to use the helpers. * tests (session benchmarks): refactor to use new Kms type * refactor (schema): rm test which relies on deprecated Kms code * refactor (kms): post rebase on main changes required * chore (kms refactor): re-add unit test from main * refactor (kms): uses migrations that don't include KMS schema changes
db package
Usage
Just some high-level usage highlights to get you started. Read the godocs for a complete list of capabilities and their documentation.
dialect = postgres.New(postgres.Config{
DSN: connectionUrl},
)
conn, _ := gorm.Open(dialect, &gorm.Config{})
// Db implements both the Reader and Writer interfaces
rw := Db{Tx: conn}
// There are writer methods like: Create, Update and Delete
// that will write Gorm struct to the db. These writer methods
// all support options for writing Oplog entries for the
// caller: WithOplog(yourWrapper, yourMetadata)
// the caller is responsible for the transaction life cycle of the writer
// and if an error is returned the caller must decide what to do with
// the transaction, which is almost always a rollback for the caller.
err = rw.Create(context.Background(), user)
// There are reader methods like: LookupByPublicId,
// LookupByName, SearchBy, LookupBy, etc
// which will lookup resources for you and scan them into your Gorm struct
err = rw.LookupByPublicId(context.Background(), foundUser)
// There's reader ScanRows that facilitates scanning rows from
// a query into your Gorm struct
where := "select * from test_users where name in ($1, $2)"
rows, err := rw.Query(context.Background(), where, []interface{}{"alice", "bob"})
defer rows.Close()
for rows.Next() {
user := db_test.NewTestUser()
// scan the row into your Gorm struct
if err := rw.ScanRows(rows, &user); err != nil {
return err
}
// Do something with the Gorm user struct
}
// DoTx is a writer function that wraps a TxHandler
// in a retryable transaction. You simply implement a
// TxHandler that does your writes and hand the handler
// to DoTx, which will wrap the writes in a retryable
// transaction with the retry attempts and backoff
// strategy you specify via options.
_, err = w.DoTx(
context.Background(),
10, // ten retries
ExpBackoff{}, // exponential backoff
func(w Writer) error {
// the TxHandler updates the user's friendly name
return w.Update(context.Background(), user, []string{"FriendlyName"},
// write oplogs for this update
WithOplog(
InitTestWrapper(t),
oplog.Metadata{
"key-only": nil,
"deployment": []string{"amex"},
"project": []string{"central-info-systems", "local-info-systems"},
},
),
)
})