internal/db: add Now method (#3887)
The Now() method returns the current transaction timestamp.
This commit is contained in:
1 parent
38536f4eef
commit
dd2b373866
2 files changed
+60
No files matched your search
@@ -70,6 +70,11 @@ type Reader interface {
|
||||
|
||||
// ScanRows will scan sql rows into the interface provided
|
||||
ScanRows(ctx context.Context, rows *sql.Rows, result any) error
|
||||
|
||||
// Now returns the current transaction timestamp. Now will return the same
|
||||
// timestamp whenever it is called within a transaction. In other words, calling
|
||||
// Now at the start and at the end of a transaction will return the same value.
|
||||
Now(ctx context.Context) (time.Time, error)
|
||||
}
|
||||
|
||||
// Writer interface defines create, update and retryable transaction handlers
|
||||
@@ -533,6 +538,27 @@ func (rw *Db) SearchWhere(ctx context.Context, resources any, where string, args
|
||||
return nil
|
||||
}
|
||||
|
||||
// Now returns the current transaction timestamp. Now will return the same
|
||||
// timestamp whenever it is called within a transaction. In other words, calling
|
||||
// Now at the start and at the end of a transaction will return the same value.
|
||||
func (rw *Db) Now(ctx context.Context) (time.Time, error) {
|
||||
const op = "db.(*Db).Now"
|
||||
// The Postgres docs define the different pre-defined time variables available:
|
||||
// https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT.
|
||||
// The value produced by this function is equivalent to current_timestamp.
|
||||
rows, err := rw.Query(ctx, "select now()", nil)
|
||||
if err != nil {
|
||||
return time.Time{}, errors.Wrap(ctx, err, op, errors.WithMsg("failed to query current timestamp"))
|
||||
}
|
||||
var now time.Time
|
||||
for rows.Next() {
|
||||
if err := rw.ScanRows(ctx, rows, &now); err != nil {
|
||||
return time.Time{}, errors.Wrap(ctx, err, op, errors.WithMsg("failed to query current timestamp"))
|
||||
}
|
||||
}
|
||||
return now, nil
|
||||
}
|
||||
|
||||
func isNil(i any) bool {
|
||||
if i == nil {
|
||||
return true
|
||||
|
||||
@@ -3193,3 +3193,37 @@ func TestDb_oplogMsgsForItems(t *testing.T) {
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestDb_Now(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
conn, _ := TestSetup(t, "postgres")
|
||||
rw := New(conn)
|
||||
ctx := context.Background()
|
||||
now, err := rw.Now(ctx)
|
||||
require.NoError(err)
|
||||
|
||||
now2, err := rw.Now(ctx)
|
||||
require.NoError(err)
|
||||
|
||||
// Calling Now() outside a transaction should result in different timestamps.
|
||||
// Using time.Equal instead of assert.Equal since it's more consistently
|
||||
// accurate for time.Time structs.
|
||||
assert.False(now.Equal(now2))
|
||||
|
||||
_, err = rw.DoTx(ctx, StdRetryCnt, ExpBackoff{}, func(r Reader, _ Writer) error {
|
||||
now3, err := r.Now(ctx)
|
||||
require.NoError(err)
|
||||
now4, err := r.Now(ctx)
|
||||
require.NoError(err)
|
||||
|
||||
// Calling Now() inside a transaction should result in the same timestamp
|
||||
assert.True(now3.Equal(now4))
|
||||
// The timestamps within the transaction should differ from those created outside.
|
||||
assert.False(now3.Equal(now))
|
||||
assert.False(now3.Equal(now2))
|
||||
|
||||
return nil
|
||||
})
|
||||
require.NoError(err)
|
||||
}
|
||||
Reference in new issue
Block a user