GetUserUsage returns aggregated usage for a single user.
(db *gorm.DB, userID, period string)
| 141 | |
| 142 | // GetUserUsage returns aggregated usage for a single user. |
| 143 | func GetUserUsage(db *gorm.DB, userID, period string) ([]UsageBucket, error) { |
| 144 | sqlite := isSQLiteDB(db) |
| 145 | since, dateFmt := periodToWindow(period, sqlite) |
| 146 | |
| 147 | bucketExpr := fmt.Sprintf("%s as bucket", dateFmt) |
| 148 | |
| 149 | query := db.Model(&UsageRecord{}). |
| 150 | Select(bucketExpr+", model, "+ |
| 151 | "SUM(prompt_tokens) as prompt_tokens, "+ |
| 152 | "SUM(completion_tokens) as completion_tokens, "+ |
| 153 | "SUM(total_tokens) as total_tokens, "+ |
| 154 | "COUNT(*) as request_count"). |
| 155 | Where("user_id = ?", userID). |
| 156 | Group("bucket, model"). |
| 157 | Order("bucket ASC") |
| 158 | |
| 159 | if !since.IsZero() { |
| 160 | query = query.Where("created_at >= ?", since) |
| 161 | } |
| 162 | |
| 163 | var buckets []UsageBucket |
| 164 | if err := query.Find(&buckets).Error; err != nil { |
| 165 | return nil, err |
| 166 | } |
| 167 | return buckets, nil |
| 168 | } |
| 169 | |
| 170 | // BackfillUsageSource sets the Source column on pre-feature usage rows. |
| 171 | // Idempotent: only touches rows where source is NULL or empty. |
no test coverage detected