22create or replace function list_user_events (p_user_id uuid, p_filters jsonb)
33returns json as $$
44 with
5- -- Parse pagination filters.
6- filters as (
7- select
8- (p_filters- >> ' limit' )::int as limit_value,
9- (p_filters- >> ' offset' )::int as offset_value
10- ),
11- -- Collect attendee events.
12- attendee_events as (
5+ -- Collect visible upcoming events once for all participation roles.
6+ visible_events as (
137 select
8+ g .community_id ,
149 e .event_id ,
1510 e .group_id ,
16- e .starts_at ,
17- g .community_id ,
18- ea .registration_answers ,
11+ e .starts_at
12+ from event e
13+ join " group" g using (group_id)
14+ where e .canceled = false
15+ and e .deleted = false
16+ and e .published = true
17+ and e .starts_at > now()
18+ and g .active = true
19+ and g .deleted = false
20+ ),
21+ -- Collect user participation roles.
22+ role_rows as (
23+ -- Attendee
24+ select
1925 case
2026 when ea .status = ' registration-questions-pending'
21- and pending_purchase .event_purchase_id is not null then ' Payment pending'
22- when ea .status = ' registration-questions-pending' then ' Registration pending'
23- else ' Attendee'
24- end as role,
25- ea .status = ' registration-questions-pending'
26- and pending_purchase .event_purchase_id is not null as pending_payment,
27- ea .status = ' registration-questions-pending'
28- and pending_purchase .event_purchase_id is null as registration_questions_pending,
27+ and pending_purchase .event_purchase_id is not null then ' pending-payment'
28+ when ea .status = ' registration-questions-pending' then ' registration-questions-pending'
29+ else ' attendee'
30+ end as attendance_status,
31+ ea .event_id ,
32+ ea .registration_answers ,
33+ ' attendee' ::text as role,
2934 case
3035 when ea .status = ' registration-questions-pending' then pending_purchase .provider_checkout_url
3136 else null
3237 end as resume_checkout_url
3338 from event_attendee ea
34- join event e using (event_id)
35- join " group" g using (group_id)
3639 left join lateral (
3740 select
3841 ep .event_purchase_id ,
@@ -47,251 +50,120 @@ returns json as $$
4750 ) pending_purchase on true
4851 where ea .user_id = p_user_id
4952 and ea .status in (' confirmed' , ' registration-questions-pending' )
50- and e .canceled = false
51- and e .deleted = false
52- and e .published = true
53- and e .starts_at > now()
54- and g .active = true
55- and g .deleted = false
56- ),
57- -- Collect host events.
58- host_events as (
53+
54+ union all
55+
56+ -- Host
5957 select
60- e .event_id ,
61- e .group_id ,
62- e .starts_at ,
63- g .community_id ,
58+ null ::text as attendance_status,
59+ eh .event_id ,
6460 null ::jsonb as registration_answers,
65- ' Host' ::text as role,
66- false as pending_payment,
67- false as registration_questions_pending,
61+ ' host' ::text as role,
6862 null ::text as resume_checkout_url
6963 from event_host eh
70- join event e using (event_id)
71- join " group" g using (group_id)
7264 where eh .user_id = p_user_id
73- and e .canceled = false
74- and e .deleted = false
75- and e .published = true
76- and e .starts_at > now()
77- and g .active = true
78- and g .deleted = false
79- ),
80- -- Collect event-level speaker events.
81- event_speaker_events as (
65+
66+ union all
67+
68+ -- Event speaker
8269 select
83- e .event_id ,
84- e .group_id ,
85- e .starts_at ,
86- g .community_id ,
70+ null ::text as attendance_status,
71+ es .event_id ,
8772 null ::jsonb as registration_answers,
88- ' Speaker' ::text as role,
89- false as pending_payment,
90- false as registration_questions_pending,
73+ ' speaker' ::text as role,
9174 null ::text as resume_checkout_url
9275 from event_speaker es
93- join event e using (event_id)
94- join " group" g using (group_id)
9576 where es .user_id = p_user_id
96- and e .canceled = false
97- and e .deleted = false
98- and e .published = true
99- and e .starts_at > now()
100- and g .active = true
101- and g .deleted = false
102- ),
103- -- Collect session-level speaker events.
104- session_speaker_events as (
77+
78+ union all
79+
80+ -- Session speaker
10581 select
106- e .event_id ,
107- e .group_id ,
108- e .starts_at ,
109- g .community_id ,
82+ null ::text as attendance_status,
83+ s .event_id ,
11084 null ::jsonb as registration_answers,
111- ' Speaker' ::text as role,
112- false as pending_payment,
113- false as registration_questions_pending,
85+ ' speaker' ::text as role,
11486 null ::text as resume_checkout_url
11587 from session_speaker ss
11688 join session s using (session_id)
117- join event e using (event_id)
118- join " group" g using (group_id)
11989 where ss .user_id = p_user_id
120- and e .canceled = false
121- and e .deleted = false
122- and e .published = true
123- and e .starts_at > now()
124- and g .active = true
125- and g .deleted = false
126- ),
127- -- Combine all user roles by event.
128- participant_roles as (
129- select
130- community_id,
131- event_id,
132- group_id,
133- pending_payment,
134- registration_answers,
135- registration_questions_pending,
136- resume_checkout_url,
137- role,
138- starts_at
139- from attendee_events
140- union all
141- select
142- community_id,
143- event_id,
144- group_id,
145- pending_payment,
146- registration_answers,
147- registration_questions_pending,
148- resume_checkout_url,
149- role,
150- starts_at
151- from host_events
152- union all
153- select
154- community_id,
155- event_id,
156- group_id,
157- pending_payment,
158- registration_answers,
159- registration_questions_pending,
160- resume_checkout_url,
161- role,
162- starts_at
163- from event_speaker_events
164- union all
165- select
166- community_id,
167- event_id,
168- group_id,
169- pending_payment,
170- registration_answers,
171- registration_questions_pending,
172- resume_checkout_url,
173- role,
174- starts_at
175- from session_speaker_events
176- ),
177- -- Deduplicate role rows for the same event.
178- unique_roles as (
179- select distinct
180- pr .community_id ,
181- pr .event_id ,
182- pr .group_id ,
183- pr .pending_payment ,
184- pr .registration_answers ,
185- pr .registration_questions_pending ,
186- pr .resume_checkout_url ,
187- pr .starts_at ,
188- pr .role
189- from participant_roles pr
19090 ),
19191 -- Aggregate roles per event.
19292 event_rows as (
19393 select
194- ur . community_id ,
195- ur . event_id ,
196- ur . group_id ,
197- bool_or( ur . pending_payment ) as pending_payment ,
198- (max (ur .registration_answers ::text ) filter (where ur .registration_answers is not null ))::jsonb
94+ max ( rr . attendance_status ) as attendance_status ,
95+ ve . community_id ,
96+ ve . event_id ,
97+ ve . group_id ,
98+ (max (rr .registration_answers ::text ) filter (where rr .registration_answers is not null ))::jsonb
19999 as registration_answers,
200- bool_or( ur . registration_questions_pending ) as registration_questions_pending ,
201- max ( ur . resume_checkout_url ) as resume_checkout_url ,
202- array_agg( ur . role order by ur . role asc ) as roles,
203- ur . starts_at
204- from unique_roles ur
205- group by ur .community_id , ur .event_id , ur .group_id , ur .starts_at
100+ max ( rr . resume_checkout_url ) as resume_checkout_url ,
101+ array_agg(distinct rr . role order by rr . role asc ) as roles ,
102+ ve . starts_at
103+ from visible_events ve
104+ join role_rows rr using (event_id)
105+ group by ve .community_id , ve .event_id , ve .group_id , ve .starts_at
206106 ),
207107 -- Select the requested page.
208108 event_rows_page as (
209109 select
110+ er .attendance_status ,
210111 er .community_id ,
211112 er .event_id ,
212113 er .group_id ,
213- er .pending_payment ,
214114 er .registration_answers ,
215- er .registration_questions_pending ,
216115 er .resume_checkout_url ,
217116 er .roles ,
218117 er .starts_at
219118 from event_rows er
220119 order by er .starts_at asc , er .event_id asc
221- offset (select offset_value from filters)
222- limit (select limit_value from filters)
223- ),
224- -- Count total events before pagination.
225- totals as (
226- select count (* )::int as total
227- from event_rows
228- ),
229- -- Render paginated events to JSON.
230- events_json as (
120+ offset (p_filters- >> ' offset' )::int
121+ limit (p_filters- >> ' limit' )::int
122+ )
123+ -- Build final payload.
124+ select json_build_object(
125+ ' events' ,
126+ (
231127 select coalesce(
232128 json_agg(
233129 json_build_object(
234- ' can_cancel_attendance' ,
235- event_rows_page .roles = array[' Attendee' ::text ]
236- and event_rows_page .registration_questions_pending = false
237- and not exists (
130+ ' event' ,
131+ get_event_summary(
132+ erp .community_id ,
133+ erp .group_id ,
134+ erp .event_id
135+ ),
136+ ' has_paid_purchase' ,
137+ exists (
238138 select 1
239139 from event_purchase ep
240- where ep .event_id = event_rows_page .event_id
140+ where ep .event_id = erp .event_id
241141 and ep .user_id = p_user_id
242142 and ep .status in (' completed' , ' refund-requested' )
243143 and ep .amount_minor > 0
244144 ),
245- ' can_complete_registration_questions' ,
246- event_rows_page .pending_payment = false
247- and (
248- event_rows_page .registration_questions_pending
249- or (
250- ' Attendee' = any(event_rows_page .roles )
251- and
252- json_array_length(
253- get_event_registration_questions(
254- event_rows_page .community_id ,
255- event_rows_page .event_id
256- )
257- ) > 0
258- and event_rows_page .starts_at > now()
259- )
260- ),
261- ' event' ,
262- get_event_summary(
263- event_rows_page .community_id ,
264- event_rows_page .group_id ,
265- event_rows_page .event_id
266- ),
267- ' pending_payment' ,
268- event_rows_page .pending_payment ,
269- ' registration_answers' ,
270- event_rows_page .registration_answers ,
271145 ' registration_questions' ,
272- get_event_registration_questions(
273- event_rows_page .community_id ,
274- event_rows_page .event_id
275- ),
276- ' registration_questions_pending' ,
277- event_rows_page .registration_questions_pending ,
278- ' resume_checkout_url' ,
279- event_rows_page .resume_checkout_url ,
146+ rq .registration_questions ,
280147 ' roles' ,
281- event_rows_page .roles
148+ erp .roles ,
149+ ' attendance_status' ,
150+ erp .attendance_status ,
151+ ' registration_answers' ,
152+ erp .registration_answers ,
153+ ' resume_checkout_url' ,
154+ erp .resume_checkout_url
282155 )
283- order by event_rows_page .starts_at asc , event_rows_page .event_id asc
156+ order by erp .starts_at asc , erp .event_id asc
284157 ),
285158 ' []' ::json
286- ) as events
287- from event_rows_page
288- )
289- -- Build final payload.
290- select json_build_object(
291- ' events ' ,
292- events_json . events ,
159+ )
160+ from event_rows_page erp
161+ cross join lateral (
162+ select get_event_registration_questions( erp . community_id , erp . event_id )
163+ as registration_questions
164+ ) rq
165+ ) ,
293166 ' total' ,
294- totals .total
295- )
296- from events_json, totals;
167+ (select count (* )::int from event_rows)
168+ );
297169$$ language sql;
0 commit comments