packages.wenpai.net/internal/telemetry/monthly.go
Ben Word 6df4a9a544
Add monthly install tracking for per-package install charts (#59)
* Add monthly install tracking for per-package install charts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Incremental aggregation with watermark, event pruning, and API fixes

Switch from full-recompute to watermark-based incremental aggregation
that only processes new events. Add 365-day event retention with pruning.
Fix migration to not seed data (avoids double-counting on first run).
Cap monthly installs API to 36 months and add error logging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Scott Walkinshaw <scott.walkinshaw@gmail.com>
2026-03-25 12:10:48 -05:00

39 lines
1 KiB
Go

package telemetry
import (
"context"
"database/sql"
"fmt"
)
// MonthlyInstall holds the install count for a single month.
type MonthlyInstall struct {
Month string `json:"month"`
Installs int `json:"installs"`
}
// GetMonthlyInstalls returns up to 36 months of install counts for a package, ordered ascending.
func GetMonthlyInstalls(ctx context.Context, db *sql.DB, packageID int64) ([]MonthlyInstall, error) {
rows, err := db.QueryContext(ctx, `
SELECT month, installs FROM (
SELECT month, installs
FROM monthly_installs
WHERE package_id = ?
ORDER BY month DESC
LIMIT 36
) ORDER BY month ASC`, packageID)
if err != nil {
return nil, fmt.Errorf("querying monthly installs: %w", err)
}
defer func() { _ = rows.Close() }()
var result []MonthlyInstall
for rows.Next() {
var m MonthlyInstall
if err := rows.Scan(&m.Month, &m.Installs); err != nil {
return nil, fmt.Errorf("scanning monthly install row: %w", err)
}
result = append(result, m)
}
return result, rows.Err()
}