|
7 | 7 | "time" |
8 | 8 |
|
9 | 9 | "github.com/jackc/pgx/v5" |
| 10 | + "github.com/jackc/pgx/v5/pgxpool" |
10 | 11 | "github.com/stretchr/testify/assert" |
11 | 12 | ) |
12 | 13 |
|
@@ -474,3 +475,54 @@ func TestIdsAreMonotonic(t *testing.T) { |
474 | 475 | assert.Equal(t, row.I, row.RowNumber) |
475 | 476 | } |
476 | 477 | } |
| 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