DatabaseCreation: seeder.sql

File seeder.sql, 20.2 KB (added by 231017, 21 hours ago)
Line 
1-- 1M users
2INSERT INTO Users (username, email, password, full_name, last_login)
3SELECT
4 substr(md5(random()::text), 1, 12),
5 substr(md5(random()::text), 1, 10) || '@gmail.com',
6 'password123',
7 'John Doe',
8 now()
9FROM generate_series(1, 1000000)
10ON CONFLICT DO NOTHING;
11
12
13INSERT INTO Roles(role_name)
14VALUES ('ADMIN'),
15 ('FREE_LISTENER'),
16 ('PREMIUM_LISTENER'),
17 ('ARTIST'),
18 ('LABEL_ADMIN');
19
20
21INSERT INTO Permissions (action, resource_type, scope) VALUES
22('PLAY', 'SONG', 'PUBLIC'),
23('PLAY', 'SONG', 'SHARED'),
24('PLAY', 'SONG', 'OWN'),
25('VIEW', 'SONG', 'PUBLIC'),
26('VIEW', 'SONG', 'SHARED'),
27('VIEW', 'SONG', 'OWN'),
28('CREATE', 'SONG', 'OWN'),
29('EDIT', 'SONG', 'OWN'),
30('DELETE', 'SONG', 'OWN'),
31('EDIT', 'SONG', 'ANY'),
32('DELETE', 'SONG', 'ANY'),
33
34('VIEW', 'ALBUM', 'PUBLIC'),
35('VIEW', 'ALBUM', 'SHARED'),
36('VIEW', 'ALBUM', 'OWN'),
37('CREATE', 'ALBUM', 'OWN'),
38('EDIT', 'ALBUM', 'OWN'),
39('DELETE', 'ALBUM', 'OWN'),
40('EDIT', 'ALBUM', 'ANY'),
41('DELETE', 'ALBUM', 'ANY'),
42
43('VIEW', 'PLAYLIST', 'PUBLIC'),
44('VIEW', 'PLAYLIST', 'SHARED'),
45('VIEW', 'PLAYLIST', 'OWN'),
46('CREATE', 'PLAYLIST', 'OWN'),
47('EDIT', 'PLAYLIST', 'OWN'),
48('DELETE', 'PLAYLIST', 'OWN'),
49('ADD_SONG', 'PLAYLIST', 'OWN'),
50('REMOVE_SONG', 'PLAYLIST', 'OWN'),
51('SHARE', 'PLAYLIST', 'OWN'),
52('DELETE', 'PLAYLIST', 'ANY');
53
54-- this table stores predefined role permissions
55-- for example
56-- (p.action = 'EDIT' AND p.resource_type = 'SONG' AND p.scope = 'ANY' AND r.role_name IN ('ADMIN','LABEL_ADMIN')) OR
57-- means that only admin and label admin users can edit a song with a scope any
58INSERT INTO role_permissions (role_id, permission_id)
59SELECT r.id, p.id
60FROM roles r
61 JOIN permissions p ON (
62 -- SONG
63 (p.action = 'PLAY' AND p.resource_type = 'SONG' AND p.scope = 'PUBLIC' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
64 (p.action = 'PLAY' AND p.resource_type = 'SONG' AND p.scope = 'SHARED' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
65 (p.action = 'PLAY' AND p.resource_type = 'SONG' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
66
67 (p.action = 'VIEW' AND p.resource_type = 'SONG' AND p.scope = 'PUBLIC' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
68 (p.action = 'VIEW' AND p.resource_type = 'SONG' AND p.scope = 'SHARED' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
69 (p.action = 'VIEW' AND p.resource_type = 'SONG' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
70
71 (p.action = 'CREATE' AND p.resource_type = 'SONG' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
72 (p.action = 'EDIT' AND p.resource_type = 'SONG' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
73 (p.action = 'DELETE' AND p.resource_type = 'SONG' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
74
75 (p.action = 'EDIT' AND p.resource_type = 'SONG' AND p.scope = 'ANY' AND r.role_name IN ('ADMIN','LABEL_ADMIN')) OR
76 (p.action = 'DELETE' AND p.resource_type = 'SONG' AND p.scope = 'ANY' AND r.role_name IN ('ADMIN','LABEL_ADMIN')) OR
77
78 -- ALBUM
79 (p.action = 'VIEW' AND p.resource_type = 'ALBUM' AND p.scope = 'PUBLIC' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
80 (p.action = 'VIEW' AND p.resource_type = 'ALBUM' AND p.scope = 'SHARED' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
81 (p.action = 'VIEW' AND p.resource_type = 'ALBUM' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
82
83 (p.action = 'CREATE' AND p.resource_type = 'ALBUM' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
84 (p.action = 'EDIT' AND p.resource_type = 'ALBUM' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
85 (p.action = 'DELETE' AND p.resource_type = 'ALBUM' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN')) OR
86
87 (p.action = 'EDIT' AND p.resource_type = 'ALBUM' AND p.scope = 'ANY' AND r.role_name IN ('ADMIN','LABEL_ADMIN')) OR
88 (p.action = 'DELETE' AND p.resource_type = 'ALBUM' AND p.scope = 'ANY' AND r.role_name IN ('ADMIN','LABEL_ADMIN')) OR
89
90 -- PLAYLIST
91 (p.action = 'VIEW' AND p.resource_type = 'PLAYLIST' AND p.scope = 'PUBLIC' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
92 (p.action = 'VIEW' AND p.resource_type = 'PLAYLIST' AND p.scope = 'SHARED' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
93 (p.action = 'VIEW' AND p.resource_type = 'PLAYLIST' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
94
95 (p.action = 'CREATE' AND p.resource_type = 'PLAYLIST' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
96 (p.action = 'EDIT' AND p.resource_type = 'PLAYLIST' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
97 (p.action = 'DELETE' AND p.resource_type = 'PLAYLIST' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
98
99 (p.action = 'ADD_SONG' AND p.resource_type = 'PLAYLIST' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
100 (p.action = 'REMOVE_SONG' AND p.resource_type = 'PLAYLIST' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
101 (p.action = 'SHARE' AND p.resource_type = 'PLAYLIST' AND p.scope = 'OWN' AND r.role_name IN ('ADMIN','ARTIST','LABEL_ADMIN','FREE_LISTENER','PREMIUM_LISTENER')) OR
102
103 (p.action = 'DELETE' AND p.resource_type = 'PLAYLIST' AND p.scope = 'ANY' AND r.role_name IN ('ADMIN','LABEL_ADMIN'))
104 );
105
106
107-- 375 labels with a random name
108INSERT INTO Labels (name)
109SELECT (
110 substr(md5(random()::text), 1, 12)
111)
112FROM generate_series(1, 375);
113
114
115-- 100K artists
116-- user_id-s 0-100.000 are artists
117INSERT INTO Artists (user_id, display_name)
118SELECT
119 id,
120 substr(md5(random()::text), 1, 12)
121FROM Users
122ORDER BY id
123LIMIT 100000
124ON CONFLICT DO NOTHING;
125
126
127-- users
128-- user_id-s 100.001-100.375 are label admins
129WITH selected_users AS (
130 SELECT id, row_number() OVER (ORDER BY id) AS rn
131 FROM Users
132 ORDER BY id
133 OFFSET 100000
134 LIMIT 375
135)
136INSERT INTO Label_Admins (label_id, user_id)
137SELECT
138 rn-100000 AS label_id,
139 id AS user_id
140FROM selected_users
141ON CONFLICT DO NOTHING;
142
143
144-- add the ARTIST role to users with ids 1-100K
145-- add the LABEL_ADMIN role to users with ids 100.001-100.375
146-- add the ADMIN role to user with user_id 1000000
147-- all other users (100.376-999.999) have either a PREMIUM_LISTENER or FREE_LISTENER role
148
149WITH roles_cte AS (
150 SELECT
151 MAX(CASE WHEN role_name = 'ARTIST' THEN id END) AS artist_id,
152 MAX(CASE WHEN role_name = 'LABEL_ADMIN' THEN id END) AS label_admin_id,
153 MAX(CASE WHEN role_name = 'PREMIUM_LISTENER' THEN id END) AS premium_id,
154 MAX(CASE WHEN role_name = 'FREE_LISTENER' THEN id END) AS free_id
155 FROM Roles
156)
157
158INSERT INTO User_Roles (user_id, role_id)
159SELECT u.id, r.artist_id
160FROM Users u
161CROSS JOIN roles_cte r
162WHERE u.id BETWEEN 1 AND 100000
163
164UNION ALL
165
166SELECT u.id, r.label_admin_id
167FROM Users u
168CROSS JOIN roles_cte r
169WHERE u.id BETWEEN 100001 AND 100375
170
171UNION ALL
172
173SELECT 1000000, 1
174
175UNION ALL
176
177SELECT
178 u.id,
179 CASE
180 WHEN (row_number() OVER (ORDER BY u.id)) % 3 = 0 THEN r.premium_id
181 ELSE r.free_id
182 END
183FROM Users u
184CROSS JOIN roles_cte r
185WHERE u.id BETWEEN 100376 AND 999999;
186
187-- 200K random follower-followed pairs with a bias
188-- most of the followers are listeners and most follow a group of 40 artists to simulate "more popular artists"
189WITH generated AS (
190 SELECT
191 -- follower
192 CASE
193 WHEN random() < 0.9 THEN
194 floor(random() * (1000000 - 100375))::bigint + 100376
195 ELSE
196 floor(random() * 100000)::bigint + 1
197 END AS follower_user_id,
198
199 -- followed
200 CASE
201 WHEN random() < 0.85 THEN -- artists
202 CASE
203 WHEN random() < 0.8 THEN
204 -- top 40 artists
205 floor(random() * 40)::bigint + 1
206 ELSE
207 -- remaining
208 floor(random() * (100000 - 40))::bigint + 41
209 END
210 ELSE
211 -- listeners
212 floor(random() * (1000000 - 100375))::bigint + 100376
213 END AS followed_user_id
214
215 FROM generate_series(1, 200000)
216)
217
218INSERT INTO Follows (follower_user_id, followed_user_id)
219SELECT DISTINCT *
220FROM generated
221WHERE follower_user_id <> followed_user_id
222LIMIT 100000;
223
224
225
226-- assign the 30% top-followed artists to labels
227WITH artist_followers AS (
228 SELECT
229 a.id AS artist_id,
230 COUNT(f.follower_user_id) AS follower_count
231 FROM Artists a
232 LEFT JOIN Follows f
233 ON f.followed_user_id = a.user_id
234 GROUP BY a.id
235),
236 ranked AS (
237 SELECT *,
238 NTILE(10) OVER (ORDER BY follower_count DESC) AS popularity_bucket
239 FROM artist_followers
240 ),
241 selected AS (
242 SELECT *
243 FROM ranked
244 WHERE popularity_bucket <= 3
245 )
246INSERT INTO Artist_Labels (artist_id, label_id, active, start_date, end_date)
247SELECT
248 s.artist_id,
249 s.artist_id%375+1,
250 TRUE,
251 CURRENT_DATE - (random() * 3650)::int,
252 NULL
253FROM selected s;
254
255
256-- first each artist is enriched with popularity and context about the labels
257WITH artist_followers AS (
258 SELECT
259 a.id AS artist_id,
260 a.user_id,
261 COUNT(f.follower_user_id) AS follower_count
262 FROM Artists a
263 LEFT JOIN Follows f
264 ON f.followed_user_id = a.user_id
265 GROUP BY a.id, a.user_id
266),
267artist_labels_active AS (
268 SELECT al.artist_id, al.label_id
269 FROM Artist_Labels al
270 WHERE al.active = TRUE
271),
272artist_full AS (
273 SELECT
274 af.artist_id,
275 af.follower_count,
276 al.label_id,
277 la.id AS label_admin_id
278 FROM artist_followers af
279 LEFT JOIN artist_labels_active al
280 ON af.artist_id = al.artist_id
281 LEFT JOIN Label_Admins la
282 ON la.label_id = al.label_id
283),
284expanded AS (
285 SELECT
286 af.*,
287 generate_series(1,
288 CASE
289 WHEN af.follower_count > 1200 THEN 100
290 ELSE (floor(random() * 40))::int -- 0-39
291 END
292) AS song_num
293 FROM artist_full af
294),
295numbered AS (
296 SELECT
297 *,
298 ROW_NUMBER() OVER (ORDER BY artist_id, song_num) AS rn,
299 COUNT(*) OVER () AS total_cnt
300 FROM expanded
301)
302INSERT INTO Songs (
303 title,
304 visibility,
305 owner_artist_id,
306 published_by_artist_id,
307 published_by_label_admin_id,
308 genre
309)
310SELECT
311 'Song_' || artist_id || '_' || song_num,
312 -- first 25% of songs are private, the rest public
313 CASE
314 WHEN rn <= total_cnt * 0.25 THEN 'PRIVATE'
315 ELSE 'PUBLIC'
316 END,
317 artist_id,
318 CASE
319 WHEN label_id IS NULL THEN artist_id
320 ELSE NULL
321 END,
322 CASE
323 WHEN label_id IS NOT NULL THEN label_admin_id
324 ELSE NULL
325 END,
326 NULL
327FROM numbered;
328
329-- assign songs to albums by giving more albums to more popular artists
330WITH artist_followers AS (
331 SELECT
332 a.id AS artist_id,
333 COUNT(f.follower_user_id) AS follower_count
334 FROM Artists a
335 LEFT JOIN Follows f ON f.followed_user_id = a.user_id
336 GROUP BY a.id
337),
338artist_labels_active AS (
339 SELECT artist_id, label_id
340 FROM Artist_Labels
341 WHERE active = TRUE
342),
343artist_full AS (
344 SELECT
345 af.artist_id,
346 af.follower_count,
347 al.label_id,
348 la.id AS label_admin_id
349 FROM artist_followers af
350 LEFT JOIN artist_labels_active al ON af.artist_id = al.artist_id
351 LEFT JOIN Label_Admins la ON la.label_id = al.label_id
352),
353expanded AS (
354 SELECT
355 af.*,
356 generate_series(
357 1,
358 CASE
359 WHEN af.follower_count > 1200
360 THEN (5 + floor(random() * 6))::int -- 5–10
361 ELSE (1 + floor(random() * 3))::int -- 1–3
362 END
363 ) AS album_num
364FROM artist_full af
365)
366INSERT INTO Albums (
367 title,
368 visibility,
369 owner_artist_id,
370 published_by_artist_id,
371 published_by_label_admin_id
372)
373SELECT
374 'Album_' || artist_id || '_' || album_num,
375 (ARRAY['PUBLIC','PRIVATE'])[floor(random()*2)+1],
376 artist_id,
377 -- solo artists publish themselves
378 CASE
379 WHEN label_id IS NULL THEN artist_id
380 ELSE NULL
381 END,
382 -- label artists published by label
383 CASE
384 WHEN label_id IS NOT NULL THEN label_admin_id
385 ELSE NULL
386 END
387
388FROM expanded
389WHERE (label_id IS NULL OR label_admin_id IS NOT NULL);
390
391
392WITH album_requirements AS (
393 -- how many tracks each album needs and get a sequence for the artist's albums
394 SELECT
395 id AS album_id,
396 owner_artist_id,
397 (5 + floor(random() * 12))::int AS needed,
398 ROW_NUMBER() OVER (PARTITION BY owner_artist_id ORDER BY id) as album_seq
399 FROM Albums
400),
401album_ranges AS (
402 -- create a start and end song index for each album
403 -- e.g. Album 1: 1-10, Album 2: 11-25, etc.
404 SELECT
405 *,
406 COALESCE(SUM(needed) OVER (PARTITION BY owner_artist_id ORDER BY album_seq ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) + 1 AS range_start,
407 SUM(needed) OVER (PARTITION BY owner_artist_id ORDER BY album_seq) AS range_end
408 FROM album_requirements
409),
410artist_songs AS (
411 -- rank every song globally per artist
412 SELECT
413 id AS song_id,
414 owner_artist_id,
415 ROW_NUMBER() OVER (PARTITION BY owner_artist_id ORDER BY random()) as global_song_rank
416 FROM Songs
417),
418final_assignment AS (
419 -- match the song rank to the album range
420 -- this ensures a song with rank 5 ONLY fits in the album covering range 1-10
421 SELECT
422 r.album_id,
423 s.song_id,
424 (s.global_song_rank - r.range_start + 1) AS track_number,
425 r.needed
426 FROM album_ranges r
427 JOIN artist_songs s
428 ON s.owner_artist_id = r.owner_artist_id
429 AND s.global_song_rank BETWEEN r.range_start AND r.range_end
430),
431validation AS (
432 -- count how many tracks we actually found for each album
433 SELECT
434 *,
435 COUNT(*) OVER (PARTITION BY album_id) as actual_count
436 FROM final_assignment
437)
438
439INSERT INTO Album_Tracks (album_id, song_id, track_number)
440SELECT album_id, song_id, track_number
441FROM validation
442WHERE actual_count >= 5;
443
444
445-- 10K playlists
446INSERT INTO Playlists (playlist_name, visibility, creator_user_id)
447SELECT
448 'Playlist_' || (floor(random() * 899624)::int + 100376) || '_' || gs,
449 CASE WHEN random() < 0.7 THEN 'PUBLIC' ELSE 'PRIVATE' END,
450 floor(random() * 899624)::int + 100376
451FROM generate_series(1, 10000) gs;
452
453-- insert 5K records into Saved_Playlists
454-- 1-20 saves per playlist
455WITH non_artist_users AS (
456 SELECT u.id
457 FROM Users u
458 LEFT JOIN Artists a ON u.id = a.user_id
459 WHERE a.user_id IS NULL
460),
461
462-- shuffle users once
463shuffled_users AS (
464 SELECT id, row_number() OVER () AS rn
465 FROM non_artist_users
466 ORDER BY random()
467),
468
469user_count AS (
470 SELECT count(*) AS cnt FROM shuffled_users
471),
472
473playlist_sample AS (
474 SELECT id AS playlist_id, creator_user_id
475 FROM Playlists
476 ORDER BY random()
477 LIMIT 5000
478),
479
480
481-- todo: check logic!
482expanded AS (
483 SELECT
484 p.playlist_id,
485 p.creator_user_id,
486 generate_series(
487 1, GREATEST(
488 1, LEAST(20, ((random() + random() + random()) * 5)::int
489 )
490 )
491 ) AS save_instance
492 FROM playlist_sample p
493),
494
495expanded_numbered AS (
496 SELECT
497 e.*,
498 row_number() OVER () AS rn
499 FROM expanded e
500),
501assigned AS (
502 SELECT
503 e.playlist_id,
504 u.id AS saved_by
505 FROM expanded_numbered e
506 JOIN user_count uc ON TRUE
507 JOIN shuffled_users u
508 ON u.rn = ((e.rn % uc.cnt) + 1)
509 WHERE u.id <> e.creator_user_id
510)
511INSERT INTO Saved_Playlists (playlist_id, saved_by)
512SELECT DISTINCT playlist_id, saved_by
513FROM assigned
514LIMIT 5000;
515
516-- assign ~125K songs to playlists by sampling random songs
517INSERT INTO playlist_tracks (playlist_id, song_id)
518SELECT p.id,
519 s.id
520FROM Playlists p
521CROSS JOIN LATERAL (
522 SELECT id
523 FROM Songs TABLESAMPLE SYSTEM (0.5) -- sample ~0.5% (~10k rows)
524 ORDER BY random() * (1.0 / sqrt(id)) + p.id * 0 -- p.id * 0 used for forcing postgres to recompute this instead of reusing the same result
525 LIMIT (5 + floor(random() * 16))
526) s;
527
528-- 1M reviews
529-- run 10x for 10M reviews
530WITH song_count AS (
531 SELECT COUNT(*) AS cnt FROM Songs
532)
533INSERT INTO Reviews (user_id, song_id, grade)
534SELECT
535 (100376 + floor(random() * (999999 - 100376 + 1)))::bigint AS user_id,
536 (1 + floor(random() * sc.cnt))::bigint AS song_id,
537 (1 + floor(random() * 5))::int AS grade
538FROM generate_series(1, 1000000),
539 song_count sc;
540
541
542-- 1M playback sessions
543-- top ~5% of songs are more favored to simulate "more popular" songs, a medium tier gets moderate attention while the rest receive very few plays
544-- timestamps are randomly distributed across the last 6 months and durations are 20-50s
545-- only public songs are eligible for playback sessions
546
547-- run 10x for 10M
548
549WITH public_songs AS (
550 SELECT id, ROW_NUMBER() OVER (ORDER BY id) AS rn
551 FROM Songs
552 WHERE visibility = 'PUBLIC'
553),
554public_song_count AS (
555 SELECT COUNT(*) AS cnt FROM public_songs
556),
557generated AS (
558 SELECT
559 t.user_id,
560 ps.id AS song_id,
561 t.started_at,
562 t.listened_ms,
563 t.listened_ms AS last_position_ms
564 FROM (
565 SELECT
566 (100376 + floor(random() * (999999 - 100376 + 1)))::bigint AS user_id,
567
568 CASE
569 WHEN random() < 0.6 THEN
570 floor(random() * (cnt * 0.05))::bigint + 1
571 WHEN random() < 0.85 THEN
572 floor(random() * (cnt * 0.15))::bigint + (cnt * 0.05)::bigint + 1
573 ELSE
574 floor(random() * (cnt * 0.80))::bigint + (cnt * 0.20)::bigint + 1
575 END AS song_rn,
576
577 NOW() - (random() * INTERVAL '6 months') AS started_at,
578
579 -- computed once per row
580 (20000 + floor(random() * 31000))::int AS listened_ms
581
582 FROM generate_series(1, 1000000), public_song_count
583 ) t
584 JOIN public_songs ps ON ps.rn = t.song_rn
585)
586INSERT INTO Playback_Sessions (
587 user_id,
588 song_id,
589 started_at,
590 listened_ms,
591 last_position_ms
592)
593SELECT *
594FROM generated;
595
596
597-- all sessions that ran for more than 30s are inserted into the songs stream table
598-- this is business logic that will later be enforced with a trigger or a job
599INSERT INTO Song_Streams (
600 playback_session_id,
601 song_id,
602 streamed_at,
603 user_id
604)
605SELECT
606 ps.id,
607 ps.song_id,
608 ps.started_at,
609 ps.user_id
610FROM Playback_Sessions ps
611WHERE ps.listened_ms >= 30000;
612
613-- example song relationship
614insert into song_relationships (source_song_id, target_song_id, relationship_type)
615VALUES (1951937, 1951936, 'REMIX'),
616 (1, 2, 'REMIX');
617
618-- example song contribution
619insert into song_contributors (song_id, artist_id, role, credit_order)
620VALUES
621 (82183, 71535, 'BACK VOCAL', 2),
622 (82183, 84285, 'PRODUCER', 3);
623
624-- create shared playlist for user 100002
625insert into playlists (visibility, creator_user_id, playlist_name, description)
626values ('SHARED', 100002, 'shared playlist', 'this is a shared playlist');
627
628-- add some songs to the new shared playlist
629insert into playlist_tracks (song_id, playlist_id)
630VALUES (1, 10001), (2, 10001), (3, 10001);
631
632-- give VIEW PLAYLIST access to user 100003
633insert into resource_shares (playlist_id, user_id, permission_id)
634values (10001, 100003, 21);