From 3e4306e47475c7eaadd1aa0c3ccc0e03406f363e Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Tue, 23 Sep 2025 23:20:41 -0700 Subject: [PATCH 1/2] Implement total_x metrics --- api/dbv1/models.go | 2 ++ api/server.go | 3 ++ api/v1_metrics_total_artists.go | 18 +++++++++++ api/v1_metrics_total_artists_test.go | 47 ++++++++++++++++++++++++++++ api/v1_metrics_total_plays.go | 17 ++++++++++ api/v1_metrics_total_plays_test.go | 42 +++++++++++++++++++++++++ api/v1_metrics_total_wallets.go | 17 ++++++++++ api/v1_metrics_total_wallets_test.go | 43 +++++++++++++++++++++++++ 8 files changed, 189 insertions(+) create mode 100644 api/v1_metrics_total_artists.go create mode 100644 api/v1_metrics_total_artists_test.go create mode 100644 api/v1_metrics_total_plays.go create mode 100644 api/v1_metrics_total_plays_test.go create mode 100644 api/v1_metrics_total_wallets.go create mode 100644 api/v1_metrics_total_wallets_test.go diff --git a/api/dbv1/models.go b/api/dbv1/models.go index ba9c9423..0bb13f3e 100644 --- a/api/dbv1/models.go +++ b/api/dbv1/models.go @@ -948,6 +948,8 @@ type ArtistCoin struct { Description pgtype.Text `json:"description"` Website pgtype.Text `json:"website"` Name string `json:"name"` + DbcPool pgtype.Text `json:"dbc_pool"` + HasDiscord bool `json:"has_discord"` } type ArtistCoinPool struct { diff --git a/api/server.go b/api/server.go index 54542768..b0856767 100644 --- a/api/server.go +++ b/api/server.go @@ -479,6 +479,9 @@ func NewApiServer(config config.Config) *ApiServer { // Metrics g.Get("/metrics/genres", app.v1MetricsGenres) g.Get("/metrics/plays", app.v1MetricsPlays) + g.Get("/metrics/total_plays", app.v1MetricsTotalPlays) + g.Get("/metrics/total_artists", app.v1MetricsTotalArtists) + g.Get("/metrics/total_wallets", app.v1MetricsTotalWallets) g.Get("/metrics/aggregates/apps/:time_range", app.v1MetricsApps) g.Get("/metrics/aggregates/routes/:time_range", app.v1MetricsRoutes) g.Get("/metrics/aggregates/routes/trailing/:time_range", app.v1MetricsRoutesTrailing) diff --git a/api/v1_metrics_total_artists.go b/api/v1_metrics_total_artists.go new file mode 100644 index 00000000..4414706d --- /dev/null +++ b/api/v1_metrics_total_artists.go @@ -0,0 +1,18 @@ +package api + +import ( + "github.com/gofiber/fiber/v2" +) + +func (app *ApiServer) v1MetricsTotalArtists(c *fiber.Ctx) error { + var total int64 + if err := app.pool.QueryRow(c.Context(), ` + SELECT COUNT(*)::bigint + FROM aggregate_user + WHERE total_track_count > 0 + `).Scan(&total); err != nil { + return err + } + + return c.JSON(fiber.Map{"data": map[string]int64{"total": total}}) +} diff --git a/api/v1_metrics_total_artists_test.go b/api/v1_metrics_total_artists_test.go new file mode 100644 index 00000000..05200e5f --- /dev/null +++ b/api/v1_metrics_total_artists_test.go @@ -0,0 +1,47 @@ +package api + +import ( + "testing" + + "api.audius.co/database" +) + +func TestMetricsTotalArtists_Empty(t *testing.T) { + app := emptyTestApp(t) + + status, body := testGet(t, app, "/v1/metrics/total_artists") + if status != 200 { + t.Fatalf("expected 200, got %d: %s", status, string(body)) + } + + jsonAssert(t, body, map[string]any{ + "data.total": 0, + }) +} + +func TestMetricsTotalArtists_WithFixtures(t *testing.T) { + app := emptyTestApp(t) + + fixtures := database.FixtureMap{ + "aggregate_user": { + {"user_id": 1, "total_track_count": 0}, + {"user_id": 2, "total_track_count": 3}, + {"user_id": 3, "total_track_count": 10}, + }, + "users": { + {"user_id": 1, "handle": "u1"}, + {"user_id": 2, "handle": "u2"}, + {"user_id": 3, "handle": "u3"}, + }, + } + database.Seed(app.pool.Replicas[0], fixtures) + + status, body := testGet(t, app, "/v1/metrics/total_artists") + if status != 200 { + t.Fatalf("expected 200, got %d: %s", status, string(body)) + } + + jsonAssert(t, body, map[string]any{ + "data.total": 2, + }) +} diff --git a/api/v1_metrics_total_plays.go b/api/v1_metrics_total_plays.go new file mode 100644 index 00000000..881d8dd6 --- /dev/null +++ b/api/v1_metrics_total_plays.go @@ -0,0 +1,17 @@ +package api + +import ( + "github.com/gofiber/fiber/v2" +) + +func (app *ApiServer) v1MetricsTotalPlays(c *fiber.Ctx) error { + var total int64 + if err := app.pool.QueryRow(c.Context(), ` + SELECT COALESCE(SUM(count), 0)::bigint + FROM aggregate_plays + `).Scan(&total); err != nil { + return err + } + + return c.JSON(fiber.Map{"data": map[string]int64{"total": total}}) +} diff --git a/api/v1_metrics_total_plays_test.go b/api/v1_metrics_total_plays_test.go new file mode 100644 index 00000000..53a9fa8b --- /dev/null +++ b/api/v1_metrics_total_plays_test.go @@ -0,0 +1,42 @@ +package api + +import ( + "testing" + + "api.audius.co/database" +) + +func TestMetricsTotalPlays_Empty(t *testing.T) { + app := emptyTestApp(t) + + status, body := testGet(t, app, "/v1/metrics/total_plays") + if status != 200 { + t.Fatalf("expected 200, got %d: %s", status, string(body)) + } + + jsonAssert(t, body, map[string]any{ + "data.total": 0, + }) +} + +func TestMetricsTotalPlays_WithFixtures(t *testing.T) { + app := emptyTestApp(t) + + fixtures := database.FixtureMap{ + "aggregate_plays": { + {"play_item_id": 1, "count": 100}, + {"play_item_id": 2, "count": 50}, + {"play_item_id": 3, "count": 30}, + }, + } + database.Seed(app.pool.Replicas[0], fixtures) + + status, body := testGet(t, app, "/v1/metrics/total_plays") + if status != 200 { + t.Fatalf("expected 200, got %d: %s", status, string(body)) + } + + jsonAssert(t, body, map[string]any{ + "data.total": 180, + }) +} diff --git a/api/v1_metrics_total_wallets.go b/api/v1_metrics_total_wallets.go new file mode 100644 index 00000000..8409134a --- /dev/null +++ b/api/v1_metrics_total_wallets.go @@ -0,0 +1,17 @@ +package api + +import ( + "github.com/gofiber/fiber/v2" +) + +func (app *ApiServer) v1MetricsTotalWallets(c *fiber.Ctx) error { + var total int64 + if err := app.pool.QueryRow(c.Context(), ` + SELECT COUNT(*)::bigint + FROM users + `).Scan(&total); err != nil { + return err + } + + return c.JSON(fiber.Map{"data": map[string]int64{"total": total}}) +} diff --git a/api/v1_metrics_total_wallets_test.go b/api/v1_metrics_total_wallets_test.go new file mode 100644 index 00000000..01d4f825 --- /dev/null +++ b/api/v1_metrics_total_wallets_test.go @@ -0,0 +1,43 @@ +package api + +import ( + "testing" + + "api.audius.co/database" +) + +func TestMetricsTotalWallets_Empty(t *testing.T) { + app := emptyTestApp(t) + + status, body := testGet(t, app, "/v1/metrics/total_wallets") + if status != 200 { + t.Fatalf("expected 200, got %d: %s", status, string(body)) + } + + jsonAssert(t, body, map[string]any{ + "data.total": 0, + }) +} + +func TestMetricsTotalWallets_WithFixtures(t *testing.T) { + app := emptyTestApp(t) + + fixtures := database.FixtureMap{ + "users": { + {"user_id": 1, "handle": "u1"}, + {"user_id": 2, "handle": "u2"}, + {"user_id": 3, "handle": "u3"}, + {"user_id": 4, "handle": "u4"}, + }, + } + database.Seed(app.pool.Replicas[0], fixtures) + + status, body := testGet(t, app, "/v1/metrics/total_wallets") + if status != 200 { + t.Fatalf("expected 200, got %d: %s", status, string(body)) + } + + jsonAssert(t, body, map[string]any{ + "data.total": 4, + }) +} From 5c1f6fec4dd12645a448c050c5d3ad3d2aa15b74 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Wed, 24 Sep 2025 10:23:53 -0700 Subject: [PATCH 2/2] Better total wallets --- api/v1_metrics_total_wallets.go | 8 ++++++-- api/v1_metrics_total_wallets_test.go | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/v1_metrics_total_wallets.go b/api/v1_metrics_total_wallets.go index 8409134a..bb5c2063 100644 --- a/api/v1_metrics_total_wallets.go +++ b/api/v1_metrics_total_wallets.go @@ -7,8 +7,12 @@ import ( func (app *ApiServer) v1MetricsTotalWallets(c *fiber.Ctx) error { var total int64 if err := app.pool.QueryRow(c.Context(), ` - SELECT COUNT(*)::bigint - FROM users + SELECT SUM(count)::bigint AS total + FROM ( + SELECT COUNT(*)::bigint AS count FROM users + UNION ALL + SELECT COUNT(*)::bigint AS count FROM sol_claimable_accounts + ) AS combined `).Scan(&total); err != nil { return err } diff --git a/api/v1_metrics_total_wallets_test.go b/api/v1_metrics_total_wallets_test.go index 01d4f825..6fc4d083 100644 --- a/api/v1_metrics_total_wallets_test.go +++ b/api/v1_metrics_total_wallets_test.go @@ -29,6 +29,11 @@ func TestMetricsTotalWallets_WithFixtures(t *testing.T) { {"user_id": 3, "handle": "u3"}, {"user_id": 4, "handle": "u4"}, }, + "sol_claimable_accounts": { + {"signature": "sig1", "instruction_index": 0, "slot": 1, "mint": "mint1", "ethereum_address": "0xabc", "account": "acc1"}, + {"signature": "sig2", "instruction_index": 0, "slot": 1, "mint": "mint2", "ethereum_address": "0xdef", "account": "acc2"}, + {"signature": "sig3", "instruction_index": 0, "slot": 1, "mint": "mint3", "ethereum_address": "0xghi", "account": "acc3"}, + }, } database.Seed(app.pool.Replicas[0], fixtures) @@ -38,6 +43,6 @@ func TestMetricsTotalWallets_WithFixtures(t *testing.T) { } jsonAssert(t, body, map[string]any{ - "data.total": 4, + "data.total": 7, }) }