rhythia-api 233.0.0 → 235.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.codex +0 -0
  2. package/.env +1 -12
  3. package/README.md +4 -4
  4. package/api/acceptInvite.ts +1 -1
  5. package/api/addCollectionMap.ts +1 -1
  6. package/api/chartPublicStats.ts +1 -1
  7. package/api/checkQualified.ts +93 -93
  8. package/api/createBeatmap.ts +53 -62
  9. package/api/createBeatmapPage.ts +1 -1
  10. package/api/createClan.ts +1 -1
  11. package/api/createCollection.ts +1 -1
  12. package/api/createInvite.ts +1 -1
  13. package/api/createSupporter.ts +1 -1
  14. package/api/deleteBeatmapPage.ts +2 -5
  15. package/api/deleteCollection.ts +1 -1
  16. package/api/deleteCollectionMap.ts +1 -1
  17. package/api/editAboutMe.ts +1 -1
  18. package/api/editClan.ts +1 -1
  19. package/api/editCollection.ts +1 -2
  20. package/api/editProfile.ts +1 -1
  21. package/api/enhancedSearch.ts +113 -113
  22. package/api/executeAdminOperation.ts +1 -22
  23. package/api/getAvatarUploadUrl.ts +1 -1
  24. package/api/getBadgeLeaders.ts +1 -1
  25. package/api/getBadgedUsers.ts +1 -1
  26. package/api/getBeatmapComments.ts +1 -1
  27. package/api/getBeatmapPage.ts +74 -106
  28. package/api/getBeatmapPageById.ts +70 -109
  29. package/api/getBeatmapStarRating.ts +1 -1
  30. package/api/getBeatmaps.ts +123 -93
  31. package/api/getClan.ts +1 -1
  32. package/api/getClans.ts +1 -1
  33. package/api/getCollection.ts +1 -1
  34. package/api/getCollections.ts +1 -1
  35. package/api/getInventory.ts +1 -1
  36. package/api/getLeaderboard.ts +1 -1
  37. package/api/getMapUploadUrl.ts +2 -2
  38. package/api/getOnlinePlayers.ts +1 -1
  39. package/api/getPassToken.ts +1 -1
  40. package/api/getProfile.ts +51 -31
  41. package/api/getPublicStats.ts +5 -5
  42. package/api/getRawStarRating.ts +1 -1
  43. package/api/getScore.ts +1 -1
  44. package/api/getStoryBeatmaps.ts +1 -1
  45. package/api/getTimestamp.ts +1 -1
  46. package/api/getUserScores.ts +19 -19
  47. package/api/getVerified.ts +1 -1
  48. package/api/getVideoUploadUrl.ts +1 -1
  49. package/api/postBeatmapComment.ts +1 -1
  50. package/api/qualifyMap.ts +97 -92
  51. package/api/rankMapsArchive.ts +20 -20
  52. package/api/searchUsers.ts +1 -1
  53. package/api/setPasskey.ts +1 -1
  54. package/api/submitScore.ts +1 -6
  55. package/api/submitScoreInternal.ts +461 -449
  56. package/api/updateBeatmapPage.ts +1 -1
  57. package/api/vetoMap.ts +101 -101
  58. package/index.ts +180 -167
  59. package/package.json +7 -12
  60. package/queries/admin_delete_user.sql +39 -39
  61. package/queries/admin_exclude_user.sql +21 -21
  62. package/queries/admin_invalidate_ranked_scores.sql +18 -18
  63. package/queries/admin_log_action.sql +10 -10
  64. package/queries/admin_profanity_clear.sql +29 -29
  65. package/queries/admin_remove_all_scores.sql +29 -29
  66. package/queries/admin_restrict_user.sql +21 -21
  67. package/queries/admin_search_users.sql +24 -24
  68. package/queries/admin_silence_user.sql +21 -21
  69. package/queries/admin_unban_user.sql +21 -21
  70. package/queries/enhanced_search.sql +217 -217
  71. package/queries/get_badge_leaderboard.sql +50 -50
  72. package/queries/get_clan_leaderboard.sql +68 -68
  73. package/queries/get_collections_v4.sql +109 -109
  74. package/queries/get_top_scores_for_beatmap.sql +44 -44
  75. package/queries/get_top_scores_for_beatmap3.sql +38 -0
  76. package/queries/get_user_by_email.sql +32 -32
  77. package/queries/get_user_scores_lastday.sql +47 -47
  78. package/queries/get_user_scores_reign.sql +31 -31
  79. package/queries/get_user_scores_top_and_stats.sql +84 -84
  80. package/queries/grant_special_badges.sql +69 -69
  81. package/types/database.ts +1288 -1248
  82. package/utils/beatmapTopScores.ts +84 -0
  83. package/utils/mapLifecycleWebhook.ts +287 -277
  84. package/utils/requestGeo.ts +13 -0
  85. package/utils/requestUtils.ts +127 -127
  86. package/utils/response.ts +11 -0
  87. package/worker.ts +189 -0
  88. package/wrangler.jsonc +10 -0
  89. package/index.html +0 -3
  90. package/vercel.json +0 -13
@@ -1,217 +1,217 @@
1
- CREATE OR REPLACE FUNCTION public.enhanced_search(search_text text, result_limit integer DEFAULT 10)
2
- RETURNS TABLE(result_type text, relevance double precision, user_id integer, user_username text, user_avatar_url text, user_about_me text, user_flag text, beatmap_page_id integer, beatmap_map_id text, beatmap_title text, beatmap_description text, beatmap_image text, beatmap_star_rating double precision, beatmap_length double precision, beatmap_status text, beatmap_tags text, beatmap_owner integer, beatmap_owner_username text, beatmap_owner_avatar text)
3
- LANGUAGE sql
4
- STABLE
5
- AS $function$
6
- WITH raw_params AS (
7
- SELECT
8
- NULLIF(BTRIM(search_text), '') AS raw_search,
9
- GREATEST(COALESCE(result_limit, 10), 1) AS limited_result_count
10
- ),
11
- params AS (
12
- SELECT
13
- raw_search,
14
- LOWER(raw_search) AS lower_search,
15
- raw_search || '%' AS prefix_search,
16
- '%' || raw_search || '%' AS contains_search,
17
- CASE
18
- WHEN raw_search IS NULL THEN NULL
19
- ELSE plainto_tsquery('simple', raw_search)
20
- END AS ts_query,
21
- limited_result_count
22
- FROM raw_params
23
- ),
24
- user_base AS (
25
- SELECT
26
- p.id,
27
- p.username,
28
- p."computedUsername" AS computed_username,
29
- p.avatar_url,
30
- p.about_me,
31
- p.flag,
32
- COALESCE(p.badges::text, '') AS badges_text,
33
- setweight(to_tsvector('simple', COALESCE(p.username, '')), 'A') ||
34
- setweight(to_tsvector('simple', COALESCE(p."computedUsername", '')), 'A') ||
35
- setweight(to_tsvector('simple', COALESCE(p.about_me, '')), 'B') ||
36
- setweight(to_tsvector('simple', COALESCE(p.flag, '')), 'C') ||
37
- setweight(to_tsvector('simple', COALESCE(p.badges::text, '')), 'C') AS search_vector
38
- FROM public.profiles p
39
- WHERE p.ban IS DISTINCT FROM 'excluded'
40
- ),
41
- user_scored AS (
42
- SELECT
43
- 'user'::text AS result_type,
44
- (
45
- CASE WHEN u.id::text = params.raw_search THEN 250 ELSE 0 END +
46
- CASE WHEN COALESCE(u.username, '') = params.raw_search THEN 220 ELSE 0 END +
47
- CASE WHEN COALESCE(u.computed_username, '') = params.lower_search THEN 215 ELSE 0 END +
48
- CASE WHEN LOWER(COALESCE(u.username, '')) = params.lower_search THEN 210 ELSE 0 END +
49
- CASE WHEN COALESCE(u.username, '') ILIKE params.prefix_search THEN 160 ELSE 0 END +
50
- CASE WHEN COALESCE(u.computed_username, '') ILIKE params.prefix_search THEN 150 ELSE 0 END +
51
- CASE WHEN COALESCE(u.username, '') ILIKE params.contains_search THEN 90 ELSE 0 END +
52
- CASE WHEN COALESCE(u.computed_username, '') ILIKE params.contains_search THEN 85 ELSE 0 END +
53
- CASE WHEN COALESCE(u.about_me, '') ILIKE params.contains_search THEN 25 ELSE 0 END +
54
- CASE WHEN COALESCE(u.flag, '') ILIKE params.prefix_search THEN 20 ELSE 0 END +
55
- CASE WHEN u.badges_text ILIKE params.contains_search THEN 15 ELSE 0 END +
56
- CASE
57
- WHEN params.ts_query IS NULL THEN 0
58
- ELSE ts_rank_cd(u.search_vector, params.ts_query) * 100
59
- END
60
- )::double precision AS relevance,
61
- u.id AS user_id,
62
- u.username AS user_username,
63
- u.avatar_url AS user_avatar_url,
64
- u.about_me AS user_about_me,
65
- u.flag AS user_flag,
66
- NULL::integer AS beatmap_page_id,
67
- NULL::text AS beatmap_map_id,
68
- NULL::text AS beatmap_title,
69
- NULL::text AS beatmap_description,
70
- NULL::text AS beatmap_image,
71
- NULL::double precision AS beatmap_star_rating,
72
- NULL::double precision AS beatmap_length,
73
- NULL::text AS beatmap_status,
74
- NULL::text AS beatmap_tags,
75
- NULL::integer AS beatmap_owner,
76
- NULL::text AS beatmap_owner_username,
77
- NULL::text AS beatmap_owner_avatar
78
- FROM user_base u
79
- CROSS JOIN params
80
- WHERE params.raw_search IS NOT NULL
81
- AND (
82
- u.id::text = params.raw_search
83
- OR COALESCE(u.username, '') ILIKE params.contains_search
84
- OR COALESCE(u.computed_username, '') ILIKE params.contains_search
85
- OR COALESCE(u.about_me, '') ILIKE params.contains_search
86
- OR COALESCE(u.flag, '') ILIKE params.contains_search
87
- OR u.badges_text ILIKE params.contains_search
88
- OR (params.ts_query IS NOT NULL AND u.search_vector @@ params.ts_query)
89
- )
90
- ),
91
- limited_users AS (
92
- SELECT *
93
- FROM user_scored
94
- WHERE relevance > 0
95
- ORDER BY relevance DESC, user_username NULLS LAST, user_id
96
- LIMIT (SELECT limited_result_count FROM params)
97
- ),
98
- beatmap_base AS (
99
- SELECT
100
- bp.id,
101
- bp."latestBeatmapHash" AS map_id,
102
- COALESCE(b.title, bp.title) AS display_title,
103
- bp.description,
104
- bp.tags,
105
- bp.genre,
106
- bp.status,
107
- bp.owner,
108
- p.username AS owner_username,
109
- p.avatar_url AS owner_avatar_url,
110
- b.image,
111
- b."starRating"::double precision AS star_rating,
112
- b.length::double precision AS beatmap_length,
113
- COALESCE(b."beatmapFile", '') AS beatmap_file,
114
- COALESCE(b."beatmapHash", '') AS beatmap_hash,
115
- COALESCE(b.difficulty::text, '') AS difficulty_text,
116
- COALESCE(b."noteCount"::text, '') AS note_count_text,
117
- COALESCE(b.playcount::text, '') AS playcount_text,
118
- setweight(to_tsvector('simple', COALESCE(COALESCE(b.title, bp.title), '')), 'A') ||
119
- setweight(to_tsvector('simple', COALESCE(bp.title, '')), 'A') ||
120
- setweight(to_tsvector('simple', COALESCE(p.username, '')), 'A') ||
121
- setweight(to_tsvector('simple', COALESCE(bp.description, '')), 'B') ||
122
- setweight(to_tsvector('simple', COALESCE(bp.tags, '')), 'B') ||
123
- setweight(to_tsvector('simple', COALESCE(bp.genre, '')), 'C') ||
124
- setweight(to_tsvector('simple', COALESCE(bp.status, '')), 'C') ||
125
- setweight(to_tsvector('simple', COALESCE(b."beatmapFile", '')), 'C') ||
126
- setweight(to_tsvector('simple', COALESCE(b."beatmapHash", '')), 'A') AS search_vector
127
- FROM public."beatmapPages" bp
128
- LEFT JOIN public.beatmaps b ON b."beatmapHash" = bp."latestBeatmapHash"
129
- LEFT JOIN public.profiles p ON p.id = bp.owner
130
- ),
131
- beatmap_scored AS (
132
- SELECT
133
- 'beatmap'::text AS result_type,
134
- (
135
- CASE WHEN bb.id::text = params.raw_search THEN 260 ELSE 0 END +
136
- CASE WHEN COALESCE(bb.map_id, '') = params.raw_search THEN 240 ELSE 0 END +
137
- CASE WHEN COALESCE(bb.display_title, '') = params.raw_search THEN 220 ELSE 0 END +
138
- CASE WHEN LOWER(COALESCE(bb.display_title, '')) = params.lower_search THEN 215 ELSE 0 END +
139
- CASE WHEN COALESCE(bb.display_title, '') ILIKE params.prefix_search THEN 160 ELSE 0 END +
140
- CASE WHEN COALESCE(bb.display_title, '') ILIKE params.contains_search THEN 90 ELSE 0 END +
141
- CASE WHEN COALESCE(bb.owner_username, '') = params.raw_search THEN 80 ELSE 0 END +
142
- CASE WHEN COALESCE(bb.owner_username, '') ILIKE params.prefix_search THEN 70 ELSE 0 END +
143
- CASE WHEN COALESCE(bb.owner_username, '') ILIKE params.contains_search THEN 50 ELSE 0 END +
144
- CASE WHEN COALESCE(bb.tags, '') ILIKE params.contains_search THEN 35 ELSE 0 END +
145
- CASE WHEN COALESCE(bb.description, '') ILIKE params.contains_search THEN 25 ELSE 0 END +
146
- CASE WHEN COALESCE(bb.genre, '') ILIKE params.contains_search THEN 15 ELSE 0 END +
147
- CASE WHEN COALESCE(bb.status, '') ILIKE params.contains_search THEN 15 ELSE 0 END +
148
- CASE WHEN COALESCE(bb.beatmap_file, '') ILIKE params.contains_search THEN 15 ELSE 0 END +
149
- CASE WHEN COALESCE(bb.beatmap_hash, '') ILIKE params.contains_search THEN 30 ELSE 0 END +
150
- CASE WHEN COALESCE(bb.owner::text, '') = params.raw_search THEN 40 ELSE 0 END +
151
- CASE WHEN COALESCE(bb.star_rating::text, '') = params.raw_search THEN 20 ELSE 0 END +
152
- CASE WHEN COALESCE(bb.beatmap_length::text, '') = params.raw_search THEN 15 ELSE 0 END +
153
- CASE WHEN COALESCE(bb.difficulty_text, '') = params.raw_search THEN 10 ELSE 0 END +
154
- CASE WHEN COALESCE(bb.note_count_text, '') = params.raw_search THEN 10 ELSE 0 END +
155
- CASE WHEN COALESCE(bb.playcount_text, '') = params.raw_search THEN 10 ELSE 0 END +
156
- CASE
157
- WHEN params.ts_query IS NULL THEN 0
158
- ELSE ts_rank_cd(bb.search_vector, params.ts_query) * 110
159
- END
160
- )::double precision AS relevance,
161
- NULL::integer AS user_id,
162
- NULL::text AS user_username,
163
- NULL::text AS user_avatar_url,
164
- NULL::text AS user_about_me,
165
- NULL::text AS user_flag,
166
- bb.id AS beatmap_page_id,
167
- bb.map_id AS beatmap_map_id,
168
- bb.display_title AS beatmap_title,
169
- bb.description AS beatmap_description,
170
- bb.image AS beatmap_image,
171
- bb.star_rating AS beatmap_star_rating,
172
- bb.beatmap_length AS beatmap_length,
173
- bb.status AS beatmap_status,
174
- bb.tags AS beatmap_tags,
175
- bb.owner AS beatmap_owner,
176
- bb.owner_username AS beatmap_owner_username,
177
- bb.owner_avatar_url AS beatmap_owner_avatar
178
- FROM beatmap_base bb
179
- CROSS JOIN params
180
- WHERE params.raw_search IS NOT NULL
181
- AND (
182
- bb.id::text = params.raw_search
183
- OR COALESCE(bb.map_id, '') ILIKE params.contains_search
184
- OR COALESCE(bb.display_title, '') ILIKE params.contains_search
185
- OR COALESCE(bb.description, '') ILIKE params.contains_search
186
- OR COALESCE(bb.tags, '') ILIKE params.contains_search
187
- OR COALESCE(bb.genre, '') ILIKE params.contains_search
188
- OR COALESCE(bb.status, '') ILIKE params.contains_search
189
- OR COALESCE(bb.owner_username, '') ILIKE params.contains_search
190
- OR COALESCE(bb.beatmap_file, '') ILIKE params.contains_search
191
- OR COALESCE(bb.beatmap_hash, '') ILIKE params.contains_search
192
- OR COALESCE(bb.owner::text, '') = params.raw_search
193
- OR COALESCE(bb.star_rating::text, '') = params.raw_search
194
- OR COALESCE(bb.beatmap_length::text, '') = params.raw_search
195
- OR COALESCE(bb.difficulty_text, '') = params.raw_search
196
- OR COALESCE(bb.note_count_text, '') = params.raw_search
197
- OR COALESCE(bb.playcount_text, '') = params.raw_search
198
- OR (params.ts_query IS NOT NULL AND bb.search_vector @@ params.ts_query)
199
- )
200
- ),
201
- limited_beatmaps AS (
202
- SELECT *
203
- FROM beatmap_scored
204
- WHERE relevance > 0
205
- ORDER BY relevance DESC, beatmap_title NULLS LAST, beatmap_page_id
206
- LIMIT (SELECT limited_result_count FROM params)
207
- )
208
- SELECT *
209
- FROM (
210
- SELECT *
211
- FROM limited_users
212
- UNION ALL
213
- SELECT *
214
- FROM limited_beatmaps
215
- ) AS combined_results
216
- ORDER BY result_type DESC, relevance DESC, COALESCE(user_username, beatmap_title) NULLS LAST, COALESCE(user_id, beatmap_page_id);
217
- $function$;
1
+ CREATE OR REPLACE FUNCTION public.enhanced_search(search_text text, result_limit integer DEFAULT 10)
2
+ RETURNS TABLE(result_type text, relevance double precision, user_id integer, user_username text, user_avatar_url text, user_about_me text, user_flag text, beatmap_page_id integer, beatmap_map_id text, beatmap_title text, beatmap_description text, beatmap_image text, beatmap_star_rating double precision, beatmap_length double precision, beatmap_status text, beatmap_tags text, beatmap_owner integer, beatmap_owner_username text, beatmap_owner_avatar text)
3
+ LANGUAGE sql
4
+ STABLE
5
+ AS $function$
6
+ WITH raw_params AS (
7
+ SELECT
8
+ NULLIF(BTRIM(search_text), '') AS raw_search,
9
+ GREATEST(COALESCE(result_limit, 10), 1) AS limited_result_count
10
+ ),
11
+ params AS (
12
+ SELECT
13
+ raw_search,
14
+ LOWER(raw_search) AS lower_search,
15
+ raw_search || '%' AS prefix_search,
16
+ '%' || raw_search || '%' AS contains_search,
17
+ CASE
18
+ WHEN raw_search IS NULL THEN NULL
19
+ ELSE plainto_tsquery('simple', raw_search)
20
+ END AS ts_query,
21
+ limited_result_count
22
+ FROM raw_params
23
+ ),
24
+ user_base AS (
25
+ SELECT
26
+ p.id,
27
+ p.username,
28
+ p."computedUsername" AS computed_username,
29
+ p.avatar_url,
30
+ p.about_me,
31
+ p.flag,
32
+ COALESCE(p.badges::text, '') AS badges_text,
33
+ setweight(to_tsvector('simple', COALESCE(p.username, '')), 'A') ||
34
+ setweight(to_tsvector('simple', COALESCE(p."computedUsername", '')), 'A') ||
35
+ setweight(to_tsvector('simple', COALESCE(p.about_me, '')), 'B') ||
36
+ setweight(to_tsvector('simple', COALESCE(p.flag, '')), 'C') ||
37
+ setweight(to_tsvector('simple', COALESCE(p.badges::text, '')), 'C') AS search_vector
38
+ FROM public.profiles p
39
+ WHERE p.ban IS DISTINCT FROM 'excluded'
40
+ ),
41
+ user_scored AS (
42
+ SELECT
43
+ 'user'::text AS result_type,
44
+ (
45
+ CASE WHEN u.id::text = params.raw_search THEN 250 ELSE 0 END +
46
+ CASE WHEN COALESCE(u.username, '') = params.raw_search THEN 220 ELSE 0 END +
47
+ CASE WHEN COALESCE(u.computed_username, '') = params.lower_search THEN 215 ELSE 0 END +
48
+ CASE WHEN LOWER(COALESCE(u.username, '')) = params.lower_search THEN 210 ELSE 0 END +
49
+ CASE WHEN COALESCE(u.username, '') ILIKE params.prefix_search THEN 160 ELSE 0 END +
50
+ CASE WHEN COALESCE(u.computed_username, '') ILIKE params.prefix_search THEN 150 ELSE 0 END +
51
+ CASE WHEN COALESCE(u.username, '') ILIKE params.contains_search THEN 90 ELSE 0 END +
52
+ CASE WHEN COALESCE(u.computed_username, '') ILIKE params.contains_search THEN 85 ELSE 0 END +
53
+ CASE WHEN COALESCE(u.about_me, '') ILIKE params.contains_search THEN 25 ELSE 0 END +
54
+ CASE WHEN COALESCE(u.flag, '') ILIKE params.prefix_search THEN 20 ELSE 0 END +
55
+ CASE WHEN u.badges_text ILIKE params.contains_search THEN 15 ELSE 0 END +
56
+ CASE
57
+ WHEN params.ts_query IS NULL THEN 0
58
+ ELSE ts_rank_cd(u.search_vector, params.ts_query) * 100
59
+ END
60
+ )::double precision AS relevance,
61
+ u.id AS user_id,
62
+ u.username AS user_username,
63
+ u.avatar_url AS user_avatar_url,
64
+ u.about_me AS user_about_me,
65
+ u.flag AS user_flag,
66
+ NULL::integer AS beatmap_page_id,
67
+ NULL::text AS beatmap_map_id,
68
+ NULL::text AS beatmap_title,
69
+ NULL::text AS beatmap_description,
70
+ NULL::text AS beatmap_image,
71
+ NULL::double precision AS beatmap_star_rating,
72
+ NULL::double precision AS beatmap_length,
73
+ NULL::text AS beatmap_status,
74
+ NULL::text AS beatmap_tags,
75
+ NULL::integer AS beatmap_owner,
76
+ NULL::text AS beatmap_owner_username,
77
+ NULL::text AS beatmap_owner_avatar
78
+ FROM user_base u
79
+ CROSS JOIN params
80
+ WHERE params.raw_search IS NOT NULL
81
+ AND (
82
+ u.id::text = params.raw_search
83
+ OR COALESCE(u.username, '') ILIKE params.contains_search
84
+ OR COALESCE(u.computed_username, '') ILIKE params.contains_search
85
+ OR COALESCE(u.about_me, '') ILIKE params.contains_search
86
+ OR COALESCE(u.flag, '') ILIKE params.contains_search
87
+ OR u.badges_text ILIKE params.contains_search
88
+ OR (params.ts_query IS NOT NULL AND u.search_vector @@ params.ts_query)
89
+ )
90
+ ),
91
+ limited_users AS (
92
+ SELECT *
93
+ FROM user_scored
94
+ WHERE relevance > 0
95
+ ORDER BY relevance DESC, user_username NULLS LAST, user_id
96
+ LIMIT (SELECT limited_result_count FROM params)
97
+ ),
98
+ beatmap_base AS (
99
+ SELECT
100
+ bp.id,
101
+ bp."latestBeatmapHash" AS map_id,
102
+ COALESCE(b.title, bp.title) AS display_title,
103
+ bp.description,
104
+ bp.tags,
105
+ bp.genre,
106
+ bp.status,
107
+ bp.owner,
108
+ p.username AS owner_username,
109
+ p.avatar_url AS owner_avatar_url,
110
+ b.image,
111
+ b."starRating"::double precision AS star_rating,
112
+ b.length::double precision AS beatmap_length,
113
+ COALESCE(b."beatmapFile", '') AS beatmap_file,
114
+ COALESCE(b."beatmapHash", '') AS beatmap_hash,
115
+ COALESCE(b.difficulty::text, '') AS difficulty_text,
116
+ COALESCE(b."noteCount"::text, '') AS note_count_text,
117
+ COALESCE(b.playcount::text, '') AS playcount_text,
118
+ setweight(to_tsvector('simple', COALESCE(COALESCE(b.title, bp.title), '')), 'A') ||
119
+ setweight(to_tsvector('simple', COALESCE(bp.title, '')), 'A') ||
120
+ setweight(to_tsvector('simple', COALESCE(p.username, '')), 'A') ||
121
+ setweight(to_tsvector('simple', COALESCE(bp.description, '')), 'B') ||
122
+ setweight(to_tsvector('simple', COALESCE(bp.tags, '')), 'B') ||
123
+ setweight(to_tsvector('simple', COALESCE(bp.genre, '')), 'C') ||
124
+ setweight(to_tsvector('simple', COALESCE(bp.status, '')), 'C') ||
125
+ setweight(to_tsvector('simple', COALESCE(b."beatmapFile", '')), 'C') ||
126
+ setweight(to_tsvector('simple', COALESCE(b."beatmapHash", '')), 'A') AS search_vector
127
+ FROM public."beatmapPages" bp
128
+ LEFT JOIN public.beatmaps b ON b."beatmapHash" = bp."latestBeatmapHash"
129
+ LEFT JOIN public.profiles p ON p.id = bp.owner
130
+ ),
131
+ beatmap_scored AS (
132
+ SELECT
133
+ 'beatmap'::text AS result_type,
134
+ (
135
+ CASE WHEN bb.id::text = params.raw_search THEN 260 ELSE 0 END +
136
+ CASE WHEN COALESCE(bb.map_id, '') = params.raw_search THEN 240 ELSE 0 END +
137
+ CASE WHEN COALESCE(bb.display_title, '') = params.raw_search THEN 220 ELSE 0 END +
138
+ CASE WHEN LOWER(COALESCE(bb.display_title, '')) = params.lower_search THEN 215 ELSE 0 END +
139
+ CASE WHEN COALESCE(bb.display_title, '') ILIKE params.prefix_search THEN 160 ELSE 0 END +
140
+ CASE WHEN COALESCE(bb.display_title, '') ILIKE params.contains_search THEN 90 ELSE 0 END +
141
+ CASE WHEN COALESCE(bb.owner_username, '') = params.raw_search THEN 80 ELSE 0 END +
142
+ CASE WHEN COALESCE(bb.owner_username, '') ILIKE params.prefix_search THEN 70 ELSE 0 END +
143
+ CASE WHEN COALESCE(bb.owner_username, '') ILIKE params.contains_search THEN 50 ELSE 0 END +
144
+ CASE WHEN COALESCE(bb.tags, '') ILIKE params.contains_search THEN 35 ELSE 0 END +
145
+ CASE WHEN COALESCE(bb.description, '') ILIKE params.contains_search THEN 25 ELSE 0 END +
146
+ CASE WHEN COALESCE(bb.genre, '') ILIKE params.contains_search THEN 15 ELSE 0 END +
147
+ CASE WHEN COALESCE(bb.status, '') ILIKE params.contains_search THEN 15 ELSE 0 END +
148
+ CASE WHEN COALESCE(bb.beatmap_file, '') ILIKE params.contains_search THEN 15 ELSE 0 END +
149
+ CASE WHEN COALESCE(bb.beatmap_hash, '') ILIKE params.contains_search THEN 30 ELSE 0 END +
150
+ CASE WHEN COALESCE(bb.owner::text, '') = params.raw_search THEN 40 ELSE 0 END +
151
+ CASE WHEN COALESCE(bb.star_rating::text, '') = params.raw_search THEN 20 ELSE 0 END +
152
+ CASE WHEN COALESCE(bb.beatmap_length::text, '') = params.raw_search THEN 15 ELSE 0 END +
153
+ CASE WHEN COALESCE(bb.difficulty_text, '') = params.raw_search THEN 10 ELSE 0 END +
154
+ CASE WHEN COALESCE(bb.note_count_text, '') = params.raw_search THEN 10 ELSE 0 END +
155
+ CASE WHEN COALESCE(bb.playcount_text, '') = params.raw_search THEN 10 ELSE 0 END +
156
+ CASE
157
+ WHEN params.ts_query IS NULL THEN 0
158
+ ELSE ts_rank_cd(bb.search_vector, params.ts_query) * 110
159
+ END
160
+ )::double precision AS relevance,
161
+ NULL::integer AS user_id,
162
+ NULL::text AS user_username,
163
+ NULL::text AS user_avatar_url,
164
+ NULL::text AS user_about_me,
165
+ NULL::text AS user_flag,
166
+ bb.id AS beatmap_page_id,
167
+ bb.map_id AS beatmap_map_id,
168
+ bb.display_title AS beatmap_title,
169
+ bb.description AS beatmap_description,
170
+ bb.image AS beatmap_image,
171
+ bb.star_rating AS beatmap_star_rating,
172
+ bb.beatmap_length AS beatmap_length,
173
+ bb.status AS beatmap_status,
174
+ bb.tags AS beatmap_tags,
175
+ bb.owner AS beatmap_owner,
176
+ bb.owner_username AS beatmap_owner_username,
177
+ bb.owner_avatar_url AS beatmap_owner_avatar
178
+ FROM beatmap_base bb
179
+ CROSS JOIN params
180
+ WHERE params.raw_search IS NOT NULL
181
+ AND (
182
+ bb.id::text = params.raw_search
183
+ OR COALESCE(bb.map_id, '') ILIKE params.contains_search
184
+ OR COALESCE(bb.display_title, '') ILIKE params.contains_search
185
+ OR COALESCE(bb.description, '') ILIKE params.contains_search
186
+ OR COALESCE(bb.tags, '') ILIKE params.contains_search
187
+ OR COALESCE(bb.genre, '') ILIKE params.contains_search
188
+ OR COALESCE(bb.status, '') ILIKE params.contains_search
189
+ OR COALESCE(bb.owner_username, '') ILIKE params.contains_search
190
+ OR COALESCE(bb.beatmap_file, '') ILIKE params.contains_search
191
+ OR COALESCE(bb.beatmap_hash, '') ILIKE params.contains_search
192
+ OR COALESCE(bb.owner::text, '') = params.raw_search
193
+ OR COALESCE(bb.star_rating::text, '') = params.raw_search
194
+ OR COALESCE(bb.beatmap_length::text, '') = params.raw_search
195
+ OR COALESCE(bb.difficulty_text, '') = params.raw_search
196
+ OR COALESCE(bb.note_count_text, '') = params.raw_search
197
+ OR COALESCE(bb.playcount_text, '') = params.raw_search
198
+ OR (params.ts_query IS NOT NULL AND bb.search_vector @@ params.ts_query)
199
+ )
200
+ ),
201
+ limited_beatmaps AS (
202
+ SELECT *
203
+ FROM beatmap_scored
204
+ WHERE relevance > 0
205
+ ORDER BY relevance DESC, beatmap_title NULLS LAST, beatmap_page_id
206
+ LIMIT (SELECT limited_result_count FROM params)
207
+ )
208
+ SELECT *
209
+ FROM (
210
+ SELECT *
211
+ FROM limited_users
212
+ UNION ALL
213
+ SELECT *
214
+ FROM limited_beatmaps
215
+ ) AS combined_results
216
+ ORDER BY result_type DESC, relevance DESC, COALESCE(user_username, beatmap_title) NULLS LAST, COALESCE(user_id, beatmap_page_id);
217
+ $function$;
@@ -1,50 +1,50 @@
1
- CREATE OR REPLACE FUNCTION public.get_badge_leaderboard(p_limit integer DEFAULT 100)
2
- RETURNS TABLE(id integer, display_name text, avatar_url text, special_badge_count integer)
3
- LANGUAGE plpgsql
4
- SECURITY DEFINER
5
- AS $function$
6
- BEGIN
7
- RETURN QUERY
8
- WITH special_badges AS (
9
- SELECT unnest(ARRAY[
10
- 'The Start of an Era',
11
- 'New Farm',
12
- 'Spinnin',
13
- 'Old Farm',
14
- 'Birb',
15
- 'Flamingos',
16
- 'Cats!'
17
- ]) AS badge_name
18
- ),
19
- user_badge_data AS (
20
- SELECT
21
- p.id::INTEGER as id,
22
- p.username,
23
- p.avatar_url,
24
- p."computedUsername",
25
- json_array_elements_text(COALESCE(p.badges, '[]'::json)) as user_badge
26
- FROM profiles p
27
- WHERE p.username IS NOT NULL
28
- AND (p.ban IS NULL OR p.ban != 'excluded')
29
- ),
30
- user_special_badge_counts AS (
31
- SELECT
32
- ubd.id,
33
- ubd.username,
34
- ubd.avatar_url,
35
- ubd."computedUsername",
36
- COUNT(DISTINCT sb.badge_name)::INTEGER as special_badge_count
37
- FROM user_badge_data ubd
38
- INNER JOIN special_badges sb ON ubd.user_badge = sb.badge_name
39
- GROUP BY ubd.id, ubd.username, ubd.avatar_url, ubd."computedUsername"
40
- )
41
- SELECT
42
- usbc.id,
43
- COALESCE(usbc."computedUsername", usbc.username) as display_name,
44
- usbc.avatar_url,
45
- usbc.special_badge_count
46
- FROM user_special_badge_counts usbc
47
- ORDER BY usbc.special_badge_count DESC, display_name ASC
48
- LIMIT p_limit;
49
- END;
50
- $function$
1
+ CREATE OR REPLACE FUNCTION public.get_badge_leaderboard(p_limit integer DEFAULT 100)
2
+ RETURNS TABLE(id integer, display_name text, avatar_url text, special_badge_count integer)
3
+ LANGUAGE plpgsql
4
+ SECURITY DEFINER
5
+ AS $function$
6
+ BEGIN
7
+ RETURN QUERY
8
+ WITH special_badges AS (
9
+ SELECT unnest(ARRAY[
10
+ 'The Start of an Era',
11
+ 'New Farm',
12
+ 'Spinnin',
13
+ 'Old Farm',
14
+ 'Birb',
15
+ 'Flamingos',
16
+ 'Cats!'
17
+ ]) AS badge_name
18
+ ),
19
+ user_badge_data AS (
20
+ SELECT
21
+ p.id::INTEGER as id,
22
+ p.username,
23
+ p.avatar_url,
24
+ p."computedUsername",
25
+ json_array_elements_text(COALESCE(p.badges, '[]'::json)) as user_badge
26
+ FROM profiles p
27
+ WHERE p.username IS NOT NULL
28
+ AND (p.ban IS NULL OR p.ban != 'excluded')
29
+ ),
30
+ user_special_badge_counts AS (
31
+ SELECT
32
+ ubd.id,
33
+ ubd.username,
34
+ ubd.avatar_url,
35
+ ubd."computedUsername",
36
+ COUNT(DISTINCT sb.badge_name)::INTEGER as special_badge_count
37
+ FROM user_badge_data ubd
38
+ INNER JOIN special_badges sb ON ubd.user_badge = sb.badge_name
39
+ GROUP BY ubd.id, ubd.username, ubd.avatar_url, ubd."computedUsername"
40
+ )
41
+ SELECT
42
+ usbc.id,
43
+ COALESCE(usbc."computedUsername", usbc.username) as display_name,
44
+ usbc.avatar_url,
45
+ usbc.special_badge_count
46
+ FROM user_special_badge_counts usbc
47
+ ORDER BY usbc.special_badge_count DESC, display_name ASC
48
+ LIMIT p_limit;
49
+ END;
50
+ $function$