Skip to content

Commit fead757

Browse files
chore(schema): regenerate dump for trending + tastemaker triggers
Adds handle_trending and handle_tastemaker functions and their on_*_user_challenge triggers to sql/01_schema.sql so the test-schema template includes them and the trending/tastemaker notification tests pass. Stacked on the comment-notifications dump regen. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent eea3fe7 commit fead757

1 file changed

Lines changed: 193 additions & 0 deletions

File tree

sql/01_schema.sql

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4703,6 +4703,92 @@ end;
47034703
$$;
47044704

47054705

4706+
--
4707+
-- Name: handle_tastemaker(); Type: FUNCTION; Schema: public; Owner: -
4708+
--
4709+
4710+
CREATE FUNCTION public.handle_tastemaker() RETURNS trigger
4711+
LANGUAGE plpgsql
4712+
AS $_$
4713+
declare
4714+
track_hex text;
4715+
track_id_int bigint;
4716+
owner_id_int int;
4717+
action_str text;
4718+
begin
4719+
-- WHEN clause on the trigger gates challenge_id='t', but defend in
4720+
-- depth here too in case the trigger is invoked another way.
4721+
if new.challenge_id <> 't' then
4722+
return null;
4723+
end if;
4724+
4725+
-- Parse trailing hex segment "<user_hex>:t:<track_hex>" → track_id.
4726+
track_hex := split_part(new.specifier, ':', 3);
4727+
if track_hex !~ '^[0-9a-f]+$' then
4728+
return null;
4729+
end if;
4730+
track_id_int := ('x' || lpad(track_hex, 16, '0'))::bit(64)::bigint;
4731+
if track_id_int <= 0 then
4732+
return null;
4733+
end if;
4734+
4735+
select t.owner_id
4736+
into owner_id_int
4737+
from tracks t
4738+
where t.track_id = track_id_int
4739+
and t.is_current = true
4740+
limit 1;
4741+
if owner_id_int is null then
4742+
return null;
4743+
end if;
4744+
4745+
-- Repost takes precedence over save when a user is in both lists for
4746+
-- the same track — matches apps' dedupe_notifications_by_group_id
4747+
-- where repost_notifications win over save_notifications.
4748+
if exists (
4749+
select 1
4750+
from reposts
4751+
where user_id = new.user_id
4752+
and repost_item_id = track_id_int
4753+
and repost_type = 'track'
4754+
and is_current = true
4755+
and is_delete = false
4756+
) then
4757+
action_str := 'repost';
4758+
else
4759+
action_str := 'save';
4760+
end if;
4761+
4762+
insert into notification
4763+
(blocknumber, user_ids, timestamp, type, specifier, group_id, data)
4764+
values
4765+
(
4766+
new.completed_blocknumber,
4767+
ARRAY[new.user_id],
4768+
new.completed_at,
4769+
'tastemaker',
4770+
track_id_int::text,
4771+
'tastemaker_user_id:' || new.user_id || ':tastemaker_item_id:' || track_id_int,
4772+
jsonb_build_object(
4773+
'tastemaker_item_id', track_id_int,
4774+
'tastemaker_item_type', 'track',
4775+
'tastemaker_item_owner_id', owner_id_int,
4776+
'action', action_str,
4777+
'tastemaker_user_id', new.user_id
4778+
)
4779+
)
4780+
on conflict do nothing;
4781+
4782+
return null;
4783+
4784+
exception
4785+
when others then
4786+
raise warning 'An error occurred in %: %', tg_name, sqlerrm;
4787+
return null;
4788+
end;
4789+
$_$;
4790+
4791+
47064792
--
47074793
-- Name: handle_track(); Type: FUNCTION; Schema: public; Owner: -
47084794
--
@@ -4954,6 +5040,99 @@ end;
49545040
$$;
49555041

49565042

5043+
--
5044+
-- Name: handle_trending(); Type: FUNCTION; Schema: public; Owner: -
5045+
--
5046+
5047+
CREATE FUNCTION public.handle_trending() RETURNS trigger
5048+
LANGUAGE plpgsql
5049+
AS $$
5050+
declare
5051+
rank_int int;
5052+
week_date date;
5053+
entity_id_str text;
5054+
entity_id_int bigint;
5055+
notif_type text;
5056+
trend_type text;
5057+
ts_epoch bigint;
5058+
data_jsonb jsonb;
5059+
begin
5060+
if new.challenge_id not in ('tt', 'tut') then
5061+
return null;
5062+
end if;
5063+
5064+
case new.challenge_id
5065+
when 'tt' then notif_type := 'trending'; trend_type := 'TRACKS';
5066+
when 'tut' then notif_type := 'trending_underground'; trend_type := 'UNDERGROUND_TRACKS';
5067+
end case;
5068+
5069+
-- Specifier: "<YYYY-MM-DD>:<rank>"
5070+
begin
5071+
week_date := split_part(new.specifier, ':', 1)::date;
5072+
rank_int := split_part(new.specifier, ':', 2)::int;
5073+
exception when others then
5074+
return null;
5075+
end;
5076+
5077+
-- Recover entity id from the trending_results row the processor wrote
5078+
-- earlier in this transaction. PK is (rank, type, version, week); we
5079+
-- pin to NEW.user_id so we ignore any unrelated version rows.
5080+
select id
5081+
into entity_id_str
5082+
from trending_results
5083+
where rank = rank_int
5084+
and type = trend_type
5085+
and week = week_date
5086+
and user_id = new.user_id
5087+
limit 1;
5088+
if entity_id_str is null then
5089+
return null;
5090+
end if;
5091+
begin
5092+
entity_id_int := entity_id_str::bigint;
5093+
exception when others then
5094+
return null;
5095+
end;
5096+
5097+
-- timestamp suffix matches apps: epoch seconds of the recompute. We
5098+
-- use completed_at which is set by UpsertUserChallenge to now() on
5099+
-- the first insert — close enough to the recompute moment.
5100+
ts_epoch := extract(epoch from new.completed_at)::bigint;
5101+
5102+
data_jsonb := jsonb_build_object(
5103+
'time_range', 'week',
5104+
'genre', 'all',
5105+
'rank', rank_int,
5106+
'track_id', entity_id_int
5107+
);
5108+
5109+
insert into notification
5110+
(blocknumber, user_ids, timestamp, type, specifier, group_id, data)
5111+
values
5112+
(
5113+
new.completed_blocknumber,
5114+
ARRAY[new.user_id],
5115+
new.completed_at,
5116+
notif_type,
5117+
entity_id_int::text,
5118+
notif_type
5119+
|| ':time_range:week:genre:all:rank:' || rank_int
5120+
|| ':track_id:' || entity_id_int
5121+
|| ':timestamp:' || ts_epoch,
5122+
data_jsonb
5123+
)
5124+
on conflict do nothing;
5125+
5126+
return null;
5127+
5128+
exception
5129+
when others then
5130+
raise warning 'An error occurred in %: %', tg_name, sqlerrm;
5131+
return null;
5132+
end;
5133+
$$;
5134+
5135+
49575136
--
49585137
-- Name: handle_usdc_purchase(); Type: FUNCTION; Schema: public; Owner: -
49595138
--
@@ -13952,6 +14131,13 @@ CREATE TRIGGER on_sol_usdc_withdrawal AFTER INSERT ON public.sol_claimable_accou
1395214131
CREATE TRIGGER on_supporter_rank_up AFTER INSERT ON public.supporter_rank_ups FOR EACH ROW EXECUTE FUNCTION public.handle_supporter_rank_up();
1395314132

1395414133

14134+
--
14135+
-- Name: user_challenges on_tastemaker_user_challenge; Type: TRIGGER; Schema: public; Owner: -
14136+
--
14137+
14138+
CREATE TRIGGER on_tastemaker_user_challenge AFTER INSERT ON public.user_challenges FOR EACH ROW WHEN (((new.challenge_id)::text = 't'::text)) EXECUTE FUNCTION public.handle_tastemaker();
14139+
14140+
1395514141
--
1395614142
-- Name: tracks on_track; Type: TRIGGER; Schema: public; Owner: -
1395714143
--
@@ -13966,6 +14152,13 @@ CREATE TRIGGER on_track AFTER INSERT OR UPDATE ON public.tracks FOR EACH ROW EXE
1396614152
CREATE TRIGGER on_track_notify_pending_purchase_revalidation AFTER INSERT OR UPDATE OF blocknumber ON public.tracks FOR EACH ROW EXECUTE FUNCTION public.notify_pending_purchase_revalidation();
1396714153

1396814154

14155+
--
14156+
-- Name: user_challenges on_trending_user_challenge; Type: TRIGGER; Schema: public; Owner: -
14157+
--
14158+
14159+
CREATE TRIGGER on_trending_user_challenge AFTER INSERT ON public.user_challenges FOR EACH ROW WHEN (((new.challenge_id)::text = ANY ((ARRAY['tt'::character varying, 'tut'::character varying])::text[]))) EXECUTE FUNCTION public.handle_trending();
14160+
14161+
1396914162
--
1397014163
-- Name: usdc_purchases on_usdc_purchase; Type: TRIGGER; Schema: public; Owner: -
1397114164
--

0 commit comments

Comments
 (0)