Your music, beautifully tracked. All yours. (coming soon) teal.fm
teal-fm atproto
at main 6.4 kB view raw
1CREATE TABLE artists ( 2 mbid UUID PRIMARY KEY, 3 name TEXT NOT NULL, 4 play_count INTEGER DEFAULT 0 5); 6 7-- releases are synologous to 'albums' 8CREATE TABLE releases ( 9 mbid UUID PRIMARY KEY, 10 name TEXT NOT NULL, 11 play_count INTEGER DEFAULT 0 12); 13 14-- recordings are synologous to 'tracks' BUT tracks can be in multiple releases! 15CREATE TABLE recordings ( 16 mbid UUID PRIMARY KEY, 17 name TEXT NOT NULL, 18 play_count INTEGER DEFAULT 0 19); 20 21CREATE TABLE plays ( 22 uri TEXT PRIMARY KEY, 23 did TEXT NOT NULL, 24 rkey TEXT NOT NULL, 25 cid TEXT NOT NULL, 26 isrc TEXT, 27 duration INTEGER, 28 track_name TEXT NOT NULL, 29 played_time TIMESTAMP WITH TIME ZONE, 30 processed_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(), 31 release_mbid UUID, 32 release_name TEXT, 33 recording_mbid UUID, 34 submission_client_agent TEXT, 35 music_service_base_domain TEXT, 36 origin_url TEXT, 37 FOREIGN KEY (release_mbid) REFERENCES releases (mbid), 38 FOREIGN KEY (recording_mbid) REFERENCES recordings (mbid) 39); 40 41CREATE INDEX idx_plays_release_mbid ON plays (release_mbid); 42 43CREATE INDEX idx_plays_recording_mbid ON plays (recording_mbid); 44 45CREATE INDEX idx_plays_played_time ON plays (played_time); 46 47CREATE INDEX idx_plays_did ON plays (did); 48 49CREATE TABLE play_to_artists ( 50 play_uri TEXT, -- references plays(uri) 51 artist_mbid UUID REFERENCES artists (mbid), 52 artist_name TEXT, -- storing here for ease of use when joining 53 PRIMARY KEY (play_uri, artist_mbid), 54 FOREIGN KEY (play_uri) REFERENCES plays (uri) 55); 56 57CREATE INDEX idx_play_to_artists_artist ON play_to_artists (artist_mbid); 58 59-- Profiles table 60CREATE TABLE profiles ( 61 did TEXT PRIMARY KEY, 62 handle TEXT, 63 display_name TEXT, 64 description TEXT, 65 description_facets JSONB, 66 avatar TEXT, -- IPLD of the image, bafy... 67 banner TEXT, 68 created_at TIMESTAMP WITH TIME ZONE 69); 70 71-- User featured items table 72CREATE TABLE featured_items ( 73 did TEXT PRIMARY KEY, 74 mbid TEXT NOT NULL, 75 type TEXT NOT NULL 76); 77 78-- Statii table (status records) 79CREATE TABLE statii ( 80 uri TEXT PRIMARY KEY, 81 did TEXT NOT NULL, 82 rkey TEXT NOT NULL, 83 cid TEXT NOT NULL, 84 record JSONB NOT NULL, 85 indexed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() 86); 87 88CREATE INDEX idx_statii_did_rkey ON statii (did, rkey); 89 90-- Materialized view for artists' play counts 91CREATE MATERIALIZED VIEW mv_artist_play_counts AS 92SELECT 93 a.mbid AS artist_mbid, 94 a.name AS artist_name, 95 COUNT(p.uri) AS play_count 96FROM 97 artists a 98 LEFT JOIN play_to_artists pta ON a.mbid = pta.artist_mbid 99 LEFT JOIN plays p ON p.uri = pta.play_uri 100GROUP BY 101 a.mbid, 102 a.name; 103 104CREATE UNIQUE INDEX idx_mv_artist_play_counts ON mv_artist_play_counts (artist_mbid); 105 106-- Materialized view for releases' play counts 107CREATE MATERIALIZED VIEW mv_release_play_counts AS 108SELECT 109 r.mbid AS release_mbid, 110 r.name AS release_name, 111 COUNT(p.uri) AS play_count 112FROM 113 releases r 114 LEFT JOIN plays p ON p.release_mbid = r.mbid 115GROUP BY 116 r.mbid, 117 r.name; 118 119CREATE UNIQUE INDEX idx_mv_release_play_counts ON mv_release_play_counts (release_mbid); 120 121-- Materialized view for recordings' play counts 122CREATE MATERIALIZED VIEW mv_recording_play_counts AS 123SELECT 124 rec.mbid AS recording_mbid, 125 rec.name AS recording_name, 126 COUNT(p.uri) AS play_count 127FROM 128 recordings rec 129 LEFT JOIN plays p ON p.recording_mbid = rec.mbid 130GROUP BY 131 rec.mbid, 132 rec.name; 133 134CREATE UNIQUE INDEX idx_mv_recording_play_counts ON mv_recording_play_counts (recording_mbid); 135 136-- Global play count materialized view 137CREATE MATERIALIZED VIEW mv_global_play_count AS 138SELECT 139 COUNT(uri) AS total_plays, 140 COUNT(DISTINCT did) AS unique_listeners 141FROM plays; 142 143CREATE UNIQUE INDEX idx_mv_global_play_count ON mv_global_play_count(total_plays); 144 145-- Top artists in the last 30 days 146CREATE MATERIALIZED VIEW mv_top_artists_30days AS 147SELECT 148 a.mbid AS artist_mbid, 149 a.name AS artist_name, 150 COUNT(p.uri) AS play_count 151FROM artists a 152INNER JOIN play_to_artists pta ON a.mbid = pta.artist_mbid 153INNER JOIN plays p ON p.uri = pta.play_uri 154WHERE p.played_time >= NOW() - INTERVAL '30 days' 155GROUP BY a.mbid, a.name 156ORDER BY COUNT(p.uri) DESC; 157 158-- Top releases in the last 30 days 159CREATE MATERIALIZED VIEW mv_top_releases_30days AS 160SELECT 161 r.mbid AS release_mbid, 162 r.name AS release_name, 163 COUNT(p.uri) AS play_count 164FROM releases r 165INNER JOIN plays p ON p.release_mbid = r.mbid 166WHERE p.played_time >= NOW() - INTERVAL '30 days' 167GROUP BY r.mbid, r.name 168ORDER BY COUNT(p.uri) DESC; 169 170-- Top artists for user in the last 30 days 171CREATE MATERIALIZED VIEW mv_top_artists_for_user_30days AS 172SELECT 173 prof.did, 174 a.mbid AS artist_mbid, 175 a.name AS artist_name, 176 COUNT(p.uri) AS play_count 177FROM artists a 178INNER JOIN play_to_artists pta ON a.mbid = pta.artist_mbid 179INNER JOIN plays p ON p.uri = pta.play_uri 180INNER JOIN profiles prof ON prof.did = p.did 181WHERE p.played_time >= NOW() - INTERVAL '30 days' 182GROUP BY prof.did, a.mbid, a.name 183ORDER BY COUNT(p.uri) DESC; 184 185-- Top artists for user in the last 7 days 186CREATE MATERIALIZED VIEW mv_top_artists_for_user_7days AS 187SELECT 188 prof.did, 189 a.mbid AS artist_mbid, 190 a.name AS artist_name, 191 COUNT(p.uri) AS play_count 192FROM artists a 193INNER JOIN play_to_artists pta ON a.mbid = pta.artist_mbid 194INNER JOIN plays p ON p.uri = pta.play_uri 195INNER JOIN profiles prof ON prof.did = p.did 196WHERE p.played_time >= NOW() - INTERVAL '7 days' 197GROUP BY prof.did, a.mbid, a.name 198ORDER BY COUNT(p.uri) DESC; 199 200-- Top releases for user in the last 30 days 201CREATE MATERIALIZED VIEW mv_top_releases_for_user_30days AS 202SELECT 203 prof.did, 204 r.mbid AS release_mbid, 205 r.name AS release_name, 206 COUNT(p.uri) AS play_count 207FROM releases r 208INNER JOIN plays p ON p.release_mbid = r.mbid 209INNER JOIN profiles prof ON prof.did = p.did 210WHERE p.played_time >= NOW() - INTERVAL '30 days' 211GROUP BY prof.did, r.mbid, r.name 212ORDER BY COUNT(p.uri) DESC; 213 214-- Top releases for user in the last 7 days 215CREATE MATERIALIZED VIEW mv_top_releases_for_user_7days AS 216SELECT 217 prof.did, 218 r.mbid AS release_mbid, 219 r.name AS release_name, 220 COUNT(p.uri) AS play_count 221FROM releases r 222INNER JOIN plays p ON p.release_mbid = r.mbid 223INNER JOIN profiles prof ON prof.did = p.did 224WHERE p.played_time >= NOW() - INTERVAL '7 days' 225GROUP BY prof.did, r.mbid, r.name 226ORDER BY COUNT(p.uri) DESC;