Skip to content

Commit 1352114

Browse files
authored
Add a test to show how to query historical balances (#30)
1 parent df5541d commit 1352114

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ For more info about prefixed ULIDs as Ids, check out this blog post: [ULID Ident
8383

8484
ULIDs are generated by first generating a [UUIDv7](<https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_7_(timestamp_and_random)>) (time-based, ordered UUID) and then converting that to a ULID via the SQL functions from https://github.com/scoville/pgsql-ulid (included in the [vendor](vendor) directory).
8585

86+
### Historical Balances
87+
88+
Each entry row records the previous and current balance for the account. This means you can look up historical account balances by finding the most recent row before the desired time.
89+
8690
### Performance
8791

8892
Performance is a notoriously hard thing to measure, since different usage patterns and different hardware can yield very different results. I have been iterating on a script in this repository to help measure performance: [performance_check.go](go/performance_check.go), so this may be a good starting point if you want to measure performance in your own setup. The numbers included below are only a guideline.

go/test/db_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
"github.com/jackc/pgx/v5"
10+
"github.com/jackc/pgx/v5/pgxpool"
1011
"github.com/stretchr/testify/assert"
1112
)
1213

@@ -474,3 +475,54 @@ func TestIdsAreMonotonic(t *testing.T) {
474475
assert.Equal(t, row.I, row.RowNumber)
475476
}
476477
}
478+
479+
func TestFindHistoricalBalanceAtGivenTime(t *testing.T) {
480+
conn := dbconn(t)
481+
ctx := t.Context()
482+
483+
account1 := createAccount(ctx, t, conn, "account 1", "USD")
484+
account2 := createAccount(ctx, t, conn, "account 2", "USD")
485+
486+
_ = createTransfer(ctx, t, conn, account1.ID, account2.ID, "10")
487+
_ = createTransfer(ctx, t, conn, account1.ID, account2.ID, "20")
488+
_ = createTransfer(ctx, t, conn, account1.ID, account2.ID, "50")
489+
490+
entries := getEntries(ctx, t, conn, account2.ID)
491+
assert.Len(t, entries, 3)
492+
493+
// Normally, we would never update the ledger. But here I'm doing it to make testing easier.
494+
_, err := conn.Exec(ctx, "update pgledger_entries set created_at = $1 where id = $2", "2025-06-01T12:00:00Z", entries[0].ID)
495+
assert.NoError(t, err)
496+
_, err = conn.Exec(ctx, "update pgledger_entries set created_at = $1 where id = $2", "2025-06-01T13:00:00Z", entries[1].ID)
497+
assert.NoError(t, err)
498+
_, err = conn.Exec(ctx, "update pgledger_entries set created_at = $1 where id = $2", "2025-06-01T14:00:00Z", entries[2].ID)
499+
assert.NoError(t, err)
500+
501+
// Current balance
502+
assert.Equal(t, "80", getAccount(ctx, t, conn, account2.ID).Balance)
503+
504+
// Historical balances
505+
assert.Equal(t, "10", accountBalanceAtTime(t, conn, account2.ID, "2025-06-01T12:00:00Z"))
506+
assert.Equal(t, "10", accountBalanceAtTime(t, conn, account2.ID, "2025-06-01T12:15:00Z"))
507+
assert.Equal(t, "30", accountBalanceAtTime(t, conn, account2.ID, "2025-06-01T13:00:00Z"))
508+
assert.Equal(t, "30", accountBalanceAtTime(t, conn, account2.ID, "2025-06-01T13:15:00Z"))
509+
assert.Equal(t, "80", accountBalanceAtTime(t, conn, account2.ID, "2025-06-01T14:00:00Z"))
510+
assert.Equal(t, "80", accountBalanceAtTime(t, conn, account2.ID, "2025-06-01T14:15:00Z"))
511+
}
512+
513+
func accountBalanceAtTime(t *testing.T, conn *pgxpool.Pool, accountID string, datetime string) string {
514+
rows, err := conn.Query(t.Context(), `
515+
select account_current_balance
516+
from pgledger_entries
517+
where account_id = $1
518+
and created_at <= $2
519+
order by created_at desc
520+
limit 1`,
521+
accountID, datetime)
522+
assert.NoError(t, err)
523+
524+
balance, err := pgx.CollectExactlyOneRow(rows, pgx.RowTo[string])
525+
assert.NoError(t, err)
526+
527+
return balance
528+
}

0 commit comments

Comments
 (0)