diff --git a/api/v1_users_balance_history.go b/api/v1_users_balance_history.go index 91e81c16..62e53041 100644 --- a/api/v1_users_balance_history.go +++ b/api/v1_users_balance_history.go @@ -96,44 +96,47 @@ func (app *ApiServer) v1UsersBalanceHistory(c *fiber.Ctx) error { return err } - // Build SQL query with granularity parameter. // First sum balance_usd across mints at each hourly snapshot to get the - // total portfolio value per hour. For 'daily', pick the latest hour within - // each day (end-of-day balance) — do NOT sum balances across hours, since - // each hour is a point-in-time snapshot, not an additive quantity. + // total portfolio value per hour. sql := ` - WITH hourly_totals AS ( - SELECT - timestamp, - SUM(balance_usd) AS balance_usd - FROM user_balance_history - WHERE user_id = @user_id - AND timestamp >= @start_time - AND timestamp <= @end_time - GROUP BY timestamp - ), - bucketed AS ( - SELECT - CASE - WHEN @granularity::text = 'daily' THEN date_trunc('day', timestamp) - ELSE timestamp - END AS bucket_timestamp, - timestamp AS source_timestamp, + SELECT + timestamp, + SUM(balance_usd) AS balance_usd + FROM user_balance_history + WHERE user_id = @user_id + AND timestamp >= @start_time + AND timestamp <= @end_time + GROUP BY timestamp + ORDER BY timestamp ASC + ` + + if params.Granularity == GranularityDaily { + // For daily, pick the latest hour within each day (end-of-day balance). + // Do not sum balances across hours, since each hour is a point-in-time + // snapshot, not an additive quantity. + sql = ` + WITH hourly_totals AS ( + SELECT + timestamp, + SUM(balance_usd) AS balance_usd + FROM user_balance_history + WHERE user_id = @user_id + AND timestamp >= @start_time + AND timestamp <= @end_time + GROUP BY timestamp + ) + SELECT DISTINCT ON (date_trunc('day', timestamp)) + date_trunc('day', timestamp) AS timestamp, balance_usd FROM hourly_totals - ) - SELECT DISTINCT ON (bucket_timestamp) - bucket_timestamp AS timestamp, - balance_usd - FROM bucketed - ORDER BY bucket_timestamp ASC, source_timestamp DESC - ` + ORDER BY date_trunc('day', hourly_totals.timestamp) ASC, hourly_totals.timestamp DESC + ` + } rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{ - "user_id": userId, - "start_time": startTime, - "end_time": endTime, - "granularity": string(params.Granularity), + "user_id": userId, + "start_time": startTime, + "end_time": endTime, }) if err != nil { return err