diff --git a/api/dbv1/db.go b/api/dbv1/db.go index 175e8ce2..2e65aa8d 100644 --- a/api/dbv1/db.go +++ b/api/dbv1/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 package dbv1 diff --git a/api/dbv1/exists.sql.go b/api/dbv1/exists.sql.go index 148531b7..a4a4f369 100644 --- a/api/dbv1/exists.sql.go +++ b/api/dbv1/exists.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: exists.sql package dbv1 diff --git a/api/dbv1/get_account_playlists.sql.go b/api/dbv1/get_account_playlists.sql.go index a1b78d02..e57c511a 100644 --- a/api/dbv1/get_account_playlists.sql.go +++ b/api/dbv1/get_account_playlists.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_account_playlists.sql package dbv1 diff --git a/api/dbv1/get_connected_wallets.sql.go b/api/dbv1/get_connected_wallets.sql.go index e1d96ab4..12617269 100644 --- a/api/dbv1/get_connected_wallets.sql.go +++ b/api/dbv1/get_connected_wallets.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_connected_wallets.sql package dbv1 diff --git a/api/dbv1/get_developer_apps.sql.go b/api/dbv1/get_developer_apps.sql.go index 80c416e8..05d886c7 100644 --- a/api/dbv1/get_developer_apps.sql.go +++ b/api/dbv1/get_developer_apps.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_developer_apps.sql package dbv1 diff --git a/api/dbv1/get_events.sql.go b/api/dbv1/get_events.sql.go index 8f33c7ea..03d7dfde 100644 --- a/api/dbv1/get_events.sql.go +++ b/api/dbv1/get_events.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_events.sql package dbv1 diff --git a/api/dbv1/get_extended_account_fields.sql.go b/api/dbv1/get_extended_account_fields.sql.go index fdd3f5a6..a3feb641 100644 --- a/api/dbv1/get_extended_account_fields.sql.go +++ b/api/dbv1/get_extended_account_fields.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_extended_account_fields.sql package dbv1 diff --git a/api/dbv1/get_genres.sql.go b/api/dbv1/get_genres.sql.go index eca10991..9edcf7be 100644 --- a/api/dbv1/get_genres.sql.go +++ b/api/dbv1/get_genres.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_genres.sql package dbv1 diff --git a/api/dbv1/get_grants.sql.go b/api/dbv1/get_grants.sql.go index 509aa285..ce3c5642 100644 --- a/api/dbv1/get_grants.sql.go +++ b/api/dbv1/get_grants.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_grants.sql package dbv1 diff --git a/api/dbv1/get_playlist_ids_by_permalink.sql.go b/api/dbv1/get_playlist_ids_by_permalink.sql.go index a890e7e2..a679af80 100644 --- a/api/dbv1/get_playlist_ids_by_permalink.sql.go +++ b/api/dbv1/get_playlist_ids_by_permalink.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_playlist_ids_by_permalink.sql package dbv1 diff --git a/api/dbv1/get_playlist_ids_by_upc.sql.go b/api/dbv1/get_playlist_ids_by_upc.sql.go index 791a38d4..aefb4eba 100644 --- a/api/dbv1/get_playlist_ids_by_upc.sql.go +++ b/api/dbv1/get_playlist_ids_by_upc.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_playlist_ids_by_upc.sql package dbv1 diff --git a/api/dbv1/get_playlists.sql.go b/api/dbv1/get_playlists.sql.go index c98c7fca..86ee6579 100644 --- a/api/dbv1/get_playlists.sql.go +++ b/api/dbv1/get_playlists.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_playlists.sql package dbv1 diff --git a/api/dbv1/get_plays.sql.go b/api/dbv1/get_plays.sql.go index b543be00..266523f6 100644 --- a/api/dbv1/get_plays.sql.go +++ b/api/dbv1/get_plays.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_plays.sql package dbv1 diff --git a/api/dbv1/get_track_ids_by_isrc.sql.go b/api/dbv1/get_track_ids_by_isrc.sql.go index 116a02e7..4e1b0227 100644 --- a/api/dbv1/get_track_ids_by_isrc.sql.go +++ b/api/dbv1/get_track_ids_by_isrc.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_track_ids_by_isrc.sql package dbv1 diff --git a/api/dbv1/get_track_ids_by_permalink.sql.go b/api/dbv1/get_track_ids_by_permalink.sql.go index 968d59b7..97fa9689 100644 --- a/api/dbv1/get_track_ids_by_permalink.sql.go +++ b/api/dbv1/get_track_ids_by_permalink.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_track_ids_by_permalink.sql package dbv1 diff --git a/api/dbv1/get_tracks.sql.go b/api/dbv1/get_tracks.sql.go index e4095d50..28fd4ebe 100644 --- a/api/dbv1/get_tracks.sql.go +++ b/api/dbv1/get_tracks.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_tracks.sql package dbv1 @@ -48,6 +48,14 @@ SELECT duration, is_downloadable, COALESCE(aggregate_plays.count, 0) as play_count, + ( + SELECT count(*)::bigint + FROM track_downloads d + WHERE (t.stem_of IS NOT NULL + AND d.parent_track_id = (t.stem_of->>'parent_track_id')::int + AND d.track_id = t.track_id) + OR (t.stem_of IS NULL AND d.parent_track_id = t.track_id) + ) AS download_count, ddex_app, pinned_comment_id, playlists_containing_track, @@ -259,6 +267,7 @@ type GetTracksRow struct { Duration pgtype.Int4 `json:"duration"` IsDownloadable bool `json:"is_downloadable"` PlayCount int64 `json:"play_count"` + DownloadCount int64 `json:"download_count"` DdexApp pgtype.Text `json:"ddex_app"` PinnedCommentID pgtype.Int4 `json:"pinned_comment_id"` PlaylistsContainingTrack []int32 `json:"playlists_containing_track"` @@ -350,6 +359,7 @@ func (q *Queries) GetTracks(ctx context.Context, arg GetTracksParams) ([]GetTrac &i.Duration, &i.IsDownloadable, &i.PlayCount, + &i.DownloadCount, &i.DdexApp, &i.PinnedCommentID, &i.PlaylistsContainingTrack, diff --git a/api/dbv1/get_undisbursed_challenges.sql.go b/api/dbv1/get_undisbursed_challenges.sql.go index a1fb20a9..1652161f 100644 --- a/api/dbv1/get_undisbursed_challenges.sql.go +++ b/api/dbv1/get_undisbursed_challenges.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_undisbursed_challenges.sql package dbv1 diff --git a/api/dbv1/get_user_for_handle.sql.go b/api/dbv1/get_user_for_handle.sql.go index addb4359..97924f4e 100644 --- a/api/dbv1/get_user_for_handle.sql.go +++ b/api/dbv1/get_user_for_handle.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_user_for_handle.sql package dbv1 diff --git a/api/dbv1/get_user_for_wallet.sql.go b/api/dbv1/get_user_for_wallet.sql.go index 3dbe1d58..732a132c 100644 --- a/api/dbv1/get_user_for_wallet.sql.go +++ b/api/dbv1/get_user_for_wallet.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_user_for_wallet.sql package dbv1 diff --git a/api/dbv1/get_users.sql.go b/api/dbv1/get_users.sql.go index 2f9dc4e2..5fabdb4a 100644 --- a/api/dbv1/get_users.sql.go +++ b/api/dbv1/get_users.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 // source: get_users.sql package dbv1 diff --git a/api/dbv1/models.go b/api/dbv1/models.go index 19840c86..bb9fdfc1 100644 --- a/api/dbv1/models.go +++ b/api/dbv1/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.29.0 +// sqlc v1.30.0 package dbv1 diff --git a/api/dbv1/queries/get_tracks.sql b/api/dbv1/queries/get_tracks.sql index dd826b1a..3062e400 100644 --- a/api/dbv1/queries/get_tracks.sql +++ b/api/dbv1/queries/get_tracks.sql @@ -33,6 +33,14 @@ SELECT duration, is_downloadable, COALESCE(aggregate_plays.count, 0) as play_count, + ( + SELECT count(*)::bigint + FROM track_downloads d + WHERE (t.stem_of IS NOT NULL + AND d.parent_track_id = (t.stem_of->>'parent_track_id')::int + AND d.track_id = t.track_id) + OR (t.stem_of IS NULL AND d.parent_track_id = t.track_id) + ) AS download_count, ddex_app, pinned_comment_id, playlists_containing_track, diff --git a/api/swagger/swagger-v1.yaml b/api/swagger/swagger-v1.yaml index 7791f0c0..70d76dd1 100644 --- a/api/swagger/swagger-v1.yaml +++ b/api/swagger/swagger-v1.yaml @@ -13992,6 +13992,7 @@ components: - is_unlisted - permalink - play_count + - download_count - preview - remix_of - repost_count @@ -14047,6 +14048,9 @@ components: type: boolean play_count: type: integer + download_count: + type: integer + description: Full track + all stems (parent) or stem-only (stem) permalink: type: string is_streamable: @@ -15458,6 +15462,7 @@ components: - is_unlisted - permalink - play_count + - download_count - preview - remix_of - repost_count @@ -15513,6 +15518,9 @@ components: type: boolean play_count: type: integer + download_count: + type: integer + description: Full track + all stems (parent) or stem-only (stem) permalink: type: string is_streamable: diff --git a/api/v1_track_test.go b/api/v1_track_test.go index 6d2803bf..14a0bf3e 100644 --- a/api/v1_track_test.go +++ b/api/v1_track_test.go @@ -1,11 +1,13 @@ package api import ( + "context" "testing" "api.audius.co/api/dbv1" "api.audius.co/trashid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGetTrack(t *testing.T) { @@ -18,9 +20,33 @@ func TestGetTrack(t *testing.T) { assert.Equal(t, 200, status) jsonAssert(t, body, map[string]any{ - "data.id": "eYJyn", - "data.title": "Culca Canyon", - "data.play_count": 0, + "data.id": "eYJyn", + "data.title": "Culca Canyon", + "data.play_count": 0, + "data.download_count": 0, + }) +} + +func TestGetTrackDownloadCount(t *testing.T) { + app := testAppWithFixtures(t) + ctx := context.Background() + require.NotNil(t, app.writePool, "test requires write pool") + + // Track 200 is "Culca Canyon" (eYJyn). Insert two download rows so download_count is 2. + _, err := app.writePool.Exec(ctx, ` + INSERT INTO track_downloads (txhash, blocknumber, parent_track_id, track_id, user_id) + VALUES ('tx-dl-1', 101, 200, 200, 1), ('tx-dl-2', 101, 200, 200, 2) + `) + require.NoError(t, err) + + var trackResponse struct { + Data dbv1.Track + } + status, body := testGet(t, app, "/v1/full/tracks/eYJyn", &trackResponse) + assert.Equal(t, 200, status) + jsonAssert(t, body, map[string]any{ + "data.id": "eYJyn", + "data.download_count": 2, }) } diff --git a/api/v1_tracks_test.go b/api/v1_tracks_test.go index 8506da73..8c0feb5a 100644 --- a/api/v1_tracks_test.go +++ b/api/v1_tracks_test.go @@ -19,8 +19,9 @@ func TestTracksEndpoint(t *testing.T) { assert.Equal(t, 200, status) jsonAssert(t, body, map[string]any{ - "data.0.id": "eYZmn", - "data.0.title": "T1", + "data.0.id": "eYZmn", + "data.0.title": "T1", + "data.0.download_count": 0, }) } @@ -31,8 +32,9 @@ func TestGetTracksByPermalink(t *testing.T) { assert.Equal(t, 200, status) jsonAssert(t, body, map[string]any{ - "data.0.id": "eYake", - "data.0.title": "track by permalink", + "data.0.id": "eYake", + "data.0.title": "track by permalink", + "data.0.download_count": 0, }) }