Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
jerry-enebeli committed Oct 11, 2024
1 parent b10d5a3 commit b7b21ee
Show file tree
Hide file tree
Showing 18 changed files with 180 additions and 516 deletions.
1 change: 1 addition & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func (a Api) Router() *gin.Engine {

// Balance routes
router.POST("/balances", a.CreateBalance)
router.GET("/balances", a.GetBalances)
router.GET("/balances/:id", a.GetBalance)

// Balance Monitor routes
Expand Down
35 changes: 35 additions & 0 deletions api/balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package api

import (
"net/http"
"strconv"

model2 "github.com/jerry-enebeli/blnk/api/model"

Expand Down Expand Up @@ -88,6 +89,40 @@ func (a Api) GetBalance(c *gin.Context) {
c.JSON(http.StatusOK, resp)
}

// GetBalances retrieves a list of balance records with pagination.
// It extracts the 'limit' and 'offset' query parameters to control pagination,
// and the 'include' query parameter to fetch additional related information.
//
// Parameters:
// - c: The Gin context containing the request and response.
//
// Responses:
// - 400 Bad Request: If there's an error retrieving the balances or invalid query parameters.
// - 200 OK: If the balances are successfully retrieved.
func (a Api) GetBalances(c *gin.Context) {
// Extract pagination parameters (limit and offset)
limit, err := strconv.Atoi(c.DefaultQuery("limit", "10")) // Default to 10 if not specified
if err != nil || limit <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid limit value"})
return
}

offset, err := strconv.Atoi(c.DefaultQuery("offset", "0")) // Default to 0 if not specified
if err != nil || offset < 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid offset value"})
return
}

// Fetch balances with pagination
resp, err := a.blnk.GetAllBalances(c.Request.Context(), limit, offset)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

c.JSON(http.StatusOK, resp)
}

// CreateBalanceMonitor creates a new balance monitor record in the system.
// It binds the incoming JSON request to a CreateBalanceMonitor object, validates it,
// and then creates the monitor record. If any errors occur during validation
Expand Down
21 changes: 20 additions & 1 deletion api/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package api

import (
"net/http"
"strconv"

model2 "github.com/jerry-enebeli/blnk/api/model"

Expand Down Expand Up @@ -95,7 +96,25 @@ func (a Api) GetLedger(c *gin.Context) {
// - 400 Bad Request: If there's an error retrieving the ledger records.
// - 200 OK: If the ledger records are successfully retrieved.
func (a Api) GetAllLedgers(c *gin.Context) {
resp, err := a.blnk.GetAllLedgers()
// Extract limit and offset from query parameters
limit := c.DefaultQuery("limit", "10") // Default limit is 10 if not provided
offset := c.DefaultQuery("offset", "0") // Default offset is 0 if not provided

// Convert limit and offset to integers
limitInt, err := strconv.Atoi(limit)
if err != nil || limitInt < 1 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"})
return
}

offsetInt, err := strconv.Atoi(offset)
if err != nil || offsetInt < 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset value"})
return
}

// Call the GetAllLedgers method with limit and offset
resp, err := a.blnk.GetAllLedgers(limitInt, offsetInt)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
Expand Down
4 changes: 2 additions & 2 deletions balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,11 @@ func (l *Blnk) GetBalanceByID(ctx context.Context, id string, include []string)
// Returns:
// - []model.Balance: A slice of Balance models.
// - error: An error if the balances could not be retrieved.
func (l *Blnk) GetAllBalances(ctx context.Context) ([]model.Balance, error) {
func (l *Blnk) GetAllBalances(ctx context.Context, limit, offset int) ([]model.Balance, error) {
_, span := balanceTracer.Start(ctx, "GetAllBalances")
defer span.End()

balances, err := l.datasource.GetAllBalances()
balances, err := l.datasource.GetAllBalances(limit, offset)
if err != nil {
span.RecordError(err)
return nil, err
Expand Down
10 changes: 6 additions & 4 deletions balance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,11 @@ func TestGetAllBalances(t *testing.T) {
rows := sqlmock.NewRows([]string{"balance_id", "balance", "credit_balance", "debit_balance", "currency", "currency_multiplier", "ledger_id", "created_at", "meta_data"}).
AddRow("test-balance", 100, 50, 50, "USD", 1.0, "test-ledger", time.Now(), `{"key":"value"}`)

mock.ExpectQuery("SELECT balance_id, balance, credit_balance, debit_balance, currency, currency_multiplier, ledger_id, created_at, meta_data FROM blnk.balances LIMIT 20").WillReturnRows(rows)
mock.ExpectQuery("SELECT balance_id, balance, credit_balance, debit_balance, currency, currency_multiplier, ledger_id, created_at, meta_data FROM blnk.balances ORDER BY created_at DESC LIMIT \\$1 OFFSET \\$2").
WithArgs(1, 1).
WillReturnRows(rows)

result, err := d.GetAllBalances(context.Background())
result, err := d.GetAllBalances(context.Background(), 1, 1)

assert.NoError(t, err)
assert.Len(t, result, 1)
Expand Down Expand Up @@ -408,8 +410,8 @@ func TestGetBalanceMonitors(t *testing.T) {
t.Fatalf("Error creating Blnk instance: %s", err)
}
balanceID := gofakeit.UUID()
rows := sqlmock.NewRows([]string{"monitor_id", "balance_id", "field", "operator", "value", "description", "call_back_url", "created_at"}).
AddRow("test-monitor", balanceID, "field", "operator", 100, "Test Monitor", gofakeit.URL(), time.Now())
rows := sqlmock.NewRows([]string{"monitor_id", "balance_id", "field", "operator", "value", "description", "call_back_url", "created_at", "precision", "precise_value"}).
AddRow("test-monitor", balanceID, "field", "operator", 100, "Test Monitor", gofakeit.URL(), time.Now(), 100, 100000)

mock.ExpectQuery("SELECT .* FROM blnk.balance_monitors WHERE balance_id =").WithArgs(balanceID).WillReturnRows(rows)

Expand Down
18 changes: 13 additions & 5 deletions database/balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,16 +408,22 @@ func (d Datasource) GetBalanceByIndicator(indicator, currency string) (*model.Ba
// It processes each balance by scanning the query result, converting numerical fields to big.Int, and parsing metadata from JSON format.
// The function returns a slice of Balance objects or an error if any issues occur during the database query or data processing.
//
// Parameters:
// - limit: The maximum number of balances to return (e.g., 20).
// - offset: The offset to start fetching balances from (for pagination).
//
// Returns:
// - []model.Balance: A slice of Balance objects containing balance information such as balance amount, credit balance, debit balance, and metadata.
// - error: An error if any occurs during the query execution, data retrieval, or JSON parsing.
func (d Datasource) GetAllBalances() ([]model.Balance, error) {
func (d Datasource) GetAllBalances(limit, offset int) ([]model.Balance, error) {

// Execute SQL query to select all balances with a limit of 20 records
rows, err := d.Conn.Query(`
SELECT balance_id, balance, credit_balance, debit_balance, currency, currency_multiplier, ledger_id, created_at, meta_data
FROM blnk.balances
LIMIT 20
`)
ORDER BY created_at DESC
LIMIT $1 OFFSET $2
`, limit, offset)
if err != nil {
return nil, err // Return error if the query fails
}
Expand Down Expand Up @@ -839,7 +845,7 @@ func (d Datasource) GetAllMonitors() ([]model.BalanceMonitor, error) {
func (d Datasource) GetBalanceMonitors(balanceID string) ([]model.BalanceMonitor, error) {
// Query the database for monitors associated with the given balance ID
rows, err := d.Conn.Query(`
SELECT monitor_id, balance_id, field, operator, value, description, call_back_url, created_at
SELECT monitor_id, balance_id, field, operator, value, description, call_back_url, created_at, precision, precise_value
FROM blnk.balance_monitors WHERE balance_id = $1
`, balanceID)
if err != nil {
Expand All @@ -853,18 +859,20 @@ func (d Datasource) GetBalanceMonitors(balanceID string) ([]model.BalanceMonitor

// Iterate through each row in the result set
for rows.Next() {
var preciseValue int64 // Temporary variable to hold the precise value as int64
monitor := model.BalanceMonitor{} // Create an empty BalanceMonitor object
condition := model.AlertCondition{} // Create an empty AlertCondition object (part of the monitor)

// Scan the row into the monitor and condition fields
err = rows.Scan(&monitor.MonitorID, &monitor.BalanceID, &condition.Field, &condition.Operator, &condition.Value, &monitor.Description, &monitor.CallBackURL, &monitor.CreatedAt)
err = rows.Scan(&monitor.MonitorID, &monitor.BalanceID, &condition.Field, &condition.Operator, &condition.Value, &monitor.Description, &monitor.CallBackURL, &monitor.CreatedAt, &condition.Precision, &preciseValue)
if err != nil {
// Return an error if scanning fails
return nil, apierror.NewAPIError(apierror.ErrInternalServer, "Failed to scan monitor data", err)
}

// Assign the scanned AlertCondition to the monitor
monitor.Condition = condition
monitor.Condition.PreciseValue = big.NewInt(preciseValue)

// Append the monitor to the slice
monitors = append(monitors, monitor)
Expand Down
27 changes: 19 additions & 8 deletions database/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,32 @@ func (d Datasource) CreateLedger(ledger model.Ledger) (model.Ledger, error) {
return ledger, nil
}

// GetAllLedgers retrieves up to 20 ledger records from the database, unmarshaling their metadata from JSON format.
// This method is limited to return 20 ledgers at a time to optimize query performance.
// GetAllLedgers retrieves a paginated list of ledger records from the database, unmarshaling their metadata from JSON format.
// This method supports pagination and can be used to efficiently retrieve all ledgers over multiple requests.
//
// Parameters:
// - limit: The maximum number of ledgers to return (e.g., 20).
// - offset: The offset to start fetching ledgers from (for pagination).
//
// Returns:
// - []model.Ledger: A slice of ledgers retrieved from the database.
// - error: An error if the query fails or if there's an issue processing the results.
func (d Datasource) GetAllLedgers() ([]model.Ledger, error) {
// Execute a query to select up to 20 ledgers from the database
rows, err := d.Conn.Query(`
func (d Datasource) GetAllLedgers(limit, offset int) ([]model.Ledger, error) {
if limit <= 0 || limit > 100 {
limit = 20 // Default limit to 20 if the provided limit is invalid or too large
}

// Execute a paginated query to select ledgers from the database
query := `
SELECT ledger_id, name, created_at, meta_data
FROM blnk.ledgers
LIMIT 20
`)
ORDER BY created_at DESC
LIMIT $1 OFFSET $2
`

rows, err := d.Conn.Query(query, limit, offset)
if err != nil {
return nil, apierror.NewAPIError(apierror.ErrInternalServer, "Failed to retrieve ledgers", err)
return nil, apierror.NewAPIError(apierror.ErrInternalServer, err.Error(), err)
}
defer rows.Close()

Expand Down
6 changes: 3 additions & 3 deletions database/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ func TestGetAllLedgers_Success(t *testing.T) {
AddRow("ldg1", "Ledger 1", time.Now(), metaDataJSON).
AddRow("ldg2", "Ledger 2", time.Now(), metaDataJSON)

mock.ExpectQuery("SELECT ledger_id, name, created_at, meta_data FROM blnk.ledgers").
mock.ExpectQuery("SELECT ledger_id, name, created_at, meta_data FROM blnk.ledgers ORDER BY created_at DESC LIMIT \\$1 OFFSET \\$2").
WithArgs(2, 0).
WillReturnRows(rows)

ledgers, err := ds.GetAllLedgers()
ledgers, err := ds.GetAllLedgers(2, 0)
assert.NoError(t, err)
assert.Len(t, ledgers, 2)
assert.Equal(t, "Ledger 1", ledgers[0].Name)
Expand Down
12 changes: 6 additions & 6 deletions database/mocks/repo_mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ func (m *MockDataSource) UpdateTransactionStatus(ctx context.Context, id string,
return args.Error(0)
}

func (m *MockDataSource) GetAllTransactions(context.Context) ([]model.Transaction, error) {
args := m.Called()
func (m *MockDataSource) GetAllTransactions(ctx context.Context, limit, offset int) ([]model.Transaction, error) {
args := m.Called(limit, offset)
return args.Get(0).([]model.Transaction), args.Error(1)
}

Expand Down Expand Up @@ -96,8 +96,8 @@ func (m *MockDataSource) CreateLedger(ledger model.Ledger) (model.Ledger, error)
return args.Get(0).(model.Ledger), args.Error(1)
}

func (m *MockDataSource) GetAllLedgers() ([]model.Ledger, error) {
args := m.Called()
func (m *MockDataSource) GetAllLedgers(limit, offset int) ([]model.Ledger, error) {
args := m.Called(limit, offset)
return args.Get(0).([]model.Ledger), args.Error(1)
}

Expand All @@ -123,8 +123,8 @@ func (m *MockDataSource) GetBalanceByIDLite(id string) (*model.Balance, error) {
return args.Get(0).(*model.Balance), args.Error(1)
}

func (m *MockDataSource) GetAllBalances() ([]model.Balance, error) {
args := m.Called()
func (m *MockDataSource) GetAllBalances(limit, offset int) ([]model.Balance, error) {
args := m.Called(limit, offset)
return args.Get(0).([]model.Balance), args.Error(1)
}

Expand Down
Loading

0 comments on commit b7b21ee

Please sign in to comment.