From e25f3fa46579669d87f8926a3df316bdc7398af4 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Thu, 1 May 2025 11:35:13 -0700 Subject: [PATCH 1/2] wip --- api/dbv1/queries/get_events.sql | 24 +++++ api/server.go | 6 ++ api/v1_unclaimed_id.go | 4 + sql/schema1.sql | 165 +++++++++++++++++++++++--------- 4 files changed, 154 insertions(+), 45 deletions(-) create mode 100644 api/dbv1/queries/get_events.sql diff --git a/api/dbv1/queries/get_events.sql b/api/dbv1/queries/get_events.sql new file mode 100644 index 00000000..f0965064 --- /dev/null +++ b/api/dbv1/queries/get_events.sql @@ -0,0 +1,24 @@ +-- name: GetEvents :many +SELECT + event_id, + entity_id, + entity_type, + event_type, + blocknumber, + created_at, + updated_at, + is_deleted, + metadata +FROM events +WHERE + -- Filter by entity_id if provided + (@entity_id::int IS NULL OR entity_id = @entity_id) + -- Filter by entity_type if provided + AND (@entity_type::text IS NULL OR entity_type = @entity_type) + -- Filter by event_type if provided + AND (@event_type::text IS NULL OR event_type = @event_type) + -- Filter deleted events by default + AND (@filter_deleted::boolean IS NULL OR is_deleted = @filter_deleted) +ORDER BY created_at DESC +LIMIT @limit +OFFSET @offset; diff --git a/api/server.go b/api/server.go index 446eb47c..b6ecee0b 100644 --- a/api/server.go +++ b/api/server.go @@ -255,6 +255,12 @@ func NewApiServer(config config.Config) *ApiServer { // Comments g.Get("/comments/unclaimed_id", app.v1CommentsUnclaimedId) + + // Events + g.Get("/events/unclaimed_id", app.v1EventsUnclaimedId) + // g.Get("/events", app.v1Events) + // g.Get("/events/all", app.v1Events) + // g.Get("/events/entity", app.v1Event) } app.Static("/", "./static") diff --git a/api/v1_unclaimed_id.go b/api/v1_unclaimed_id.go index a4e6bb8d..73fb520d 100644 --- a/api/v1_unclaimed_id.go +++ b/api/v1_unclaimed_id.go @@ -51,3 +51,7 @@ func (app *ApiServer) v1PlaylistsUnclaimedId(c *fiber.Ctx) error { func (app *ApiServer) v1CommentsUnclaimedId(c *fiber.Ctx) error { return app.v1UnclaimedId(c, "comments", "comment_id", 4_000_000, math.MaxInt32) } + +func (app *ApiServer) v1EventsUnclaimedId(c *fiber.Ctx) error { + return app.v1UnclaimedId(c, "events", "event_id", 1, math.MaxInt32) +} diff --git a/sql/schema1.sql b/sql/schema1.sql index 62660989..c87114ca 100644 --- a/sql/schema1.sql +++ b/sql/schema1.sql @@ -1225,6 +1225,25 @@ end; $$; +-- +-- Name: compute_user_score(bigint, bigint, bigint, bigint, bigint, boolean, bigint); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.compute_user_score(play_count bigint, follower_count bigint, challenge_count bigint, chat_block_count bigint, following_count bigint, is_audius_impersonator boolean, distinct_tracks_played bigint) RETURNS bigint + LANGUAGE sql IMMUTABLE + AS $$ +select (play_count / 2) + follower_count - challenge_count - (chat_block_count * 100) + case + when following_count < 5 then -1 + else 0 + end + case + when is_audius_impersonator then -1000 + else 0 + end + case + when distinct_tracks_played <= 3 then -10 + else 0 + end $$; + + -- -- Name: country_to_iso_alpha2(text); Type: FUNCTION; Schema: public; Owner: - -- @@ -1746,11 +1765,87 @@ end; $$; +-- +-- Name: get_user_score(integer); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.get_user_score(target_user_id integer) RETURNS TABLE(user_id integer, handle_lc text, play_count bigint, distinct_tracks_played bigint, follower_count bigint, challenge_count bigint, following_count bigint, chat_block_count bigint, is_audius_impersonator boolean, score bigint) + LANGUAGE sql + AS $$ with play_activity as ( + select p.user_id, + count(distinct date_trunc('hour', p.created_at)) as play_count, + count(distinct p.play_item_id) as distinct_tracks_played + from plays p + where p.user_id = target_user_id + group by p.user_id + ), + fast_challenge_completion as ( + select u.user_id, + u.handle_lc, + u.created_at, + count(*) as challenge_count, + array_agg(uc.challenge_id) as challenge_ids + from users u + left join user_challenges uc on u.user_id = uc.user_id + where u.user_id = target_user_id + and uc.is_complete + and uc.completed_at - u.created_at <= interval '3 minutes' + and uc.challenge_id not in ('m', 'b') + group by u.user_id, + u.handle_lc, + u.created_at + ), + chat_blocks as ( + select c.blockee_user_id as user_id, + count(*) as block_count + from chat_blocked_users c + where c.blockee_user_id = target_user_id + group by c.blockee_user_id + ), + aggregate_scores as ( + select u.user_id, + u.handle_lc, + coalesce(p.play_count, 0) as play_count, + coalesce(p.distinct_tracks_played, 0) as distinct_tracks_played, + coalesce(c.challenge_count, 0) as challenge_count, + coalesce(au.following_count, 0) as following_count, + coalesce(au.follower_count, 0) as follower_count, + coalesce(cb.block_count, 0) as chat_block_count, + case + when ( + u.handle_lc ilike '%audius%' + or lower(u.name) ilike '%audius%' + ) + and u.is_verified = false then true + else false + end as is_audius_impersonator + from users u + left join play_activity p on u.user_id = p.user_id + left join fast_challenge_completion c on u.user_id = c.user_id + left join chat_blocks cb on u.user_id = cb.user_id + left join aggregate_user au on u.user_id = au.user_id + where u.user_id = target_user_id + and u.handle_lc is not null + ) +select a.*, + compute_user_score( + a.play_count, + a.follower_count, + a.challenge_count, + a.chat_block_count, + a.following_count, + a.is_audius_impersonator, + a.distinct_tracks_played + ) as score +from aggregate_scores a; +$$; + + -- -- Name: get_user_scores(integer[]); Type: FUNCTION; Schema: public; Owner: - -- -CREATE FUNCTION public.get_user_scores(target_user_ids integer[] DEFAULT NULL::integer[]) RETURNS TABLE(user_id integer, handle_lc text, play_count bigint, distinct_tracks_played bigint, follower_count bigint, challenge_count bigint, following_count bigint, chat_block_count bigint, is_audius_impersonator boolean, score bigint) +CREATE FUNCTION public.get_user_scores(target_user_ids integer[] DEFAULT NULL::integer[]) RETURNS TABLE(user_id integer, handle_lc text, play_count bigint, distinct_tracks_played bigint, follower_count bigint, following_count bigint, challenge_count bigint, chat_block_count bigint, is_audius_impersonator boolean, score bigint) LANGUAGE sql AS $$ with play_activity as ( select plays.user_id, @@ -1793,7 +1888,12 @@ CREATE FUNCTION public.get_user_scores(target_user_ids integer[] DEFAULT NULL::i aggregate_scores as ( select users.user_id, users.handle_lc, - users.created_at, + coalesce(play_activity.play_count, 0) as play_count, + coalesce(play_activity.distinct_tracks_played, 0) as distinct_tracks_played, + coalesce(aggregate_user.following_count, 0) as following_count, + coalesce(aggregate_user.follower_count, 0) as follower_count, + coalesce(fast_challenge_completion.challenge_count, 0) as challenge_count, + coalesce(chat_blocks.block_count, 0) as chat_block_count, case when ( users.handle_lc ilike '%audius%' @@ -1801,13 +1901,7 @@ CREATE FUNCTION public.get_user_scores(target_user_ids integer[] DEFAULT NULL::i ) and users.is_verified = false then true else false - end as is_audius_impersonator, - coalesce(play_activity.play_count, 0) as play_count, - coalesce(play_activity.distinct_tracks_played, 0) as distinct_tracks_played, - coalesce(fast_challenge_completion.challenge_count, 0) as challenge_count, - coalesce(aggregate_user.following_count, 0) as following_count, - coalesce(aggregate_user.follower_count, 0) as follower_count, - coalesce(chat_blocks.block_count, 0) as chat_block_count + end as is_audius_impersonator from users left join play_activity on users.user_id = play_activity.user_id left join fast_challenge_completion on users.user_id = fast_challenge_completion.user_id @@ -1819,26 +1913,15 @@ CREATE FUNCTION public.get_user_scores(target_user_ids integer[] DEFAULT NULL::i or users.user_id = any(target_user_ids) ) ) -select a.user_id, - a.handle_lc, - a.play_count, - a.distinct_tracks_played, - a.follower_count, - a.challenge_count, - a.following_count, - a.chat_block_count, - a.is_audius_impersonator, - ( - (a.play_count / 2) + a.follower_count - a.challenge_count - (a.chat_block_count * 100) + case - when a.following_count < 5 then -1 - else 0 - end + case - when a.is_audius_impersonator then -1000 - else 0 - end + case - when a.distinct_tracks_played <= 3 then -10 - else 0 - end +select a.*, + compute_user_score( + a.play_count, + a.follower_count, + a.challenge_count, + a.chat_block_count, + a.following_count, + a.is_audius_impersonator, + a.distinct_tracks_played ) as score from aggregate_scores a; $$; @@ -2343,7 +2426,6 @@ declare delta int := 0; begin - insert into aggregate_user (user_id) values (new.playlist_owner_id) on conflict do nothing; insert into aggregate_playlist (playlist_id, is_album) values (new.playlist_id, new.is_album) on conflict do nothing; with expanded as ( @@ -9760,31 +9842,31 @@ CREATE INDEX remixes_child_idx ON public.remixes USING btree (child_track_id, pa -- --- Name: reposts_new_blocknumber_idx; Type: INDEX; Schema: public; Owner: - +-- Name: reposts_item_idx; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX reposts_new_blocknumber_idx ON public.reposts USING btree (blocknumber); +CREATE INDEX reposts_item_idx ON public.reposts USING btree (repost_item_id, repost_type, user_id, is_delete); -- --- Name: reposts_new_created_at_idx; Type: INDEX; Schema: public; Owner: - +-- Name: reposts_new_blocknumber_idx; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX reposts_new_created_at_idx ON public.reposts USING btree (created_at); +CREATE INDEX reposts_new_blocknumber_idx ON public.reposts USING btree (blocknumber); -- --- Name: reposts_new_repost_item_id_repost_type_idx; Type: INDEX; Schema: public; Owner: - +-- Name: reposts_new_created_at_idx; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX reposts_new_repost_item_id_repost_type_idx ON public.reposts USING btree (repost_item_id, repost_type); +CREATE INDEX reposts_new_created_at_idx ON public.reposts USING btree (created_at); -- --- Name: reposts_new_user_id_repost_type_idx; Type: INDEX; Schema: public; Owner: - +-- Name: reposts_user_idx; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX reposts_new_user_id_repost_type_idx ON public.reposts USING btree (user_id, repost_type); +CREATE INDEX reposts_user_idx ON public.reposts USING btree (user_id, repost_type, repost_item_id, created_at, is_delete); -- @@ -9808,13 +9890,6 @@ CREATE INDEX saves_item_idx ON public.saves USING btree (save_item_id, save_type CREATE INDEX saves_new_blocknumber_idx ON public.saves USING btree (blocknumber); --- --- Name: saves_new_user_id_save_type_idx; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX saves_new_user_id_save_type_idx ON public.saves USING btree (user_id, save_type); - - -- -- Name: saves_user_idx; Type: INDEX; Schema: public; Owner: - -- From b357185a259605f5ea1f583bb260945d873cef4b Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Thu, 1 May 2025 17:30:37 -0700 Subject: [PATCH 2/2] [API-51] Implement events --- api/dbv1/full_events.go | 42 +++++++++++++++ api/dbv1/get_events.sql.go | 96 +++++++++++++++++++++++++++++++++ api/dbv1/jsonb_types.go | 5 ++ api/dbv1/models.go | 2 +- api/dbv1/queries/get_events.sql | 29 +++++----- api/fixture_test.go | 16 ++++++ api/server.go | 6 +-- api/server_test.go | 1 + api/testdata/event_fixtures.csv | 7 +++ api/testdata/user_fixtures.csv | 2 + api/v1_events.go | 44 +++++++++++++++ api/v1_events_test.go | 53 ++++++++++++++++++ sqlc.yaml | 5 ++ static/apidiff.html | 3 ++ 14 files changed, 291 insertions(+), 20 deletions(-) create mode 100644 api/dbv1/full_events.go create mode 100644 api/dbv1/get_events.sql.go create mode 100644 api/testdata/event_fixtures.csv create mode 100644 api/v1_events.go create mode 100644 api/v1_events_test.go diff --git a/api/dbv1/full_events.go b/api/dbv1/full_events.go new file mode 100644 index 00000000..8eb74cf6 --- /dev/null +++ b/api/dbv1/full_events.go @@ -0,0 +1,42 @@ +package dbv1 + +import ( + "context" + + "bridgerton.audius.co/trashid" +) + +type FullEvent struct { + GetEventsRow + + EventId trashid.HashId `json:"event_id"` + UserId trashid.HashId `json:"user_id"` + EntityId trashid.HashId `json:"entity_id"` +} + +func (q *Queries) FullEventsKeyed(ctx context.Context, arg GetEventsParams) (map[int32]FullEvent, error) { + events, err := q.GetEvents(ctx, arg) + if err != nil { + return nil, err + } + eventMap := map[int32]FullEvent{} + for _, event := range events { + eventMap[int32(event.EventID)] = FullEvent{ + GetEventsRow: event, + EventId: trashid.HashId(event.EventID), + UserId: trashid.HashId(event.UserID), + EntityId: trashid.HashId(event.EntityID.Int32), + } + } + + return eventMap, nil +} + +func (q *Queries) ToFullEvent(event GetEventsRow) FullEvent { + return FullEvent{ + GetEventsRow: event, + EventId: trashid.HashId(event.EventID), + UserId: trashid.HashId(event.UserID), + EntityId: trashid.HashId(event.EntityID.Int32), + } +} diff --git a/api/dbv1/get_events.sql.go b/api/dbv1/get_events.sql.go new file mode 100644 index 00000000..4251b086 --- /dev/null +++ b/api/dbv1/get_events.sql.go @@ -0,0 +1,96 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 +// source: get_events.sql + +package dbv1 + +import ( + "context" + "time" + + "github.com/jackc/pgx/v5/pgtype" +) + +const getEvents = `-- name: GetEvents :many +SELECT + event_id, + entity_type::event_entity_type, + user_id, + entity_id, + event_type::event_type, + end_date, + is_deleted, + created_at, + updated_at, + event_data +FROM events +WHERE + ($1::int[] = '{}' OR entity_id = ANY($1::int[])) + AND ($2::text = '' OR entity_type = $2::event_entity_type) + AND ($3::text = '' OR event_type = $3::event_type) + AND ($4::boolean IS NULL OR is_deleted = $4) +ORDER BY created_at DESC, event_id ASC +LIMIT $6 +OFFSET $5 +` + +type GetEventsParams struct { + EntityIds []int32 `json:"entity_ids"` + EntityType string `json:"entity_type"` + EventType string `json:"event_type"` + FilterDeleted bool `json:"filter_deleted"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetEventsRow struct { + EventID int32 `json:"event_id"` + EntityType EventEntityType `json:"entity_type"` + UserID int32 `json:"user_id"` + EntityID pgtype.Int4 `json:"entity_id"` + EventType EventType `json:"event_type"` + EndDate *time.Time `json:"end_date"` + IsDeleted pgtype.Bool `json:"is_deleted"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + EventData *EventData `json:"event_data"` +} + +func (q *Queries) GetEvents(ctx context.Context, arg GetEventsParams) ([]GetEventsRow, error) { + rows, err := q.db.Query(ctx, getEvents, + arg.EntityIds, + arg.EntityType, + arg.EventType, + arg.FilterDeleted, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetEventsRow + for rows.Next() { + var i GetEventsRow + if err := rows.Scan( + &i.EventID, + &i.EntityType, + &i.UserID, + &i.EntityID, + &i.EventType, + &i.EndDate, + &i.IsDeleted, + &i.CreatedAt, + &i.UpdatedAt, + &i.EventData, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/api/dbv1/jsonb_types.go b/api/dbv1/jsonb_types.go index efe2132b..b12f5017 100644 --- a/api/dbv1/jsonb_types.go +++ b/api/dbv1/jsonb_types.go @@ -54,3 +54,8 @@ type FullRemixOfTrack struct { type FullRemixOf struct { Tracks []FullRemixOfTrack `json:"tracks"` } + +type EventData struct { + PrizeInfo string `json:"prize_info"` + Description string `json:"description"` +} diff --git a/api/dbv1/models.go b/api/dbv1/models.go index 15650964..896dda7e 100644 --- a/api/dbv1/models.go +++ b/api/dbv1/models.go @@ -1235,7 +1235,7 @@ type Event struct { EntityID pgtype.Int4 `json:"entity_id"` EndDate *time.Time `json:"end_date"` IsDeleted pgtype.Bool `json:"is_deleted"` - EventData []byte `json:"event_data"` + EventData *EventData `json:"event_data"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` Txhash string `json:"txhash"` diff --git a/api/dbv1/queries/get_events.sql b/api/dbv1/queries/get_events.sql index f0965064..3171c747 100644 --- a/api/dbv1/queries/get_events.sql +++ b/api/dbv1/queries/get_events.sql @@ -1,24 +1,21 @@ -- name: GetEvents :many SELECT event_id, + entity_type::event_entity_type, + user_id, entity_id, - entity_type, - event_type, - blocknumber, + event_type::event_type, + end_date, + is_deleted, created_at, updated_at, - is_deleted, - metadata + event_data FROM events -WHERE - -- Filter by entity_id if provided - (@entity_id::int IS NULL OR entity_id = @entity_id) - -- Filter by entity_type if provided - AND (@entity_type::text IS NULL OR entity_type = @entity_type) - -- Filter by event_type if provided - AND (@event_type::text IS NULL OR event_type = @event_type) - -- Filter deleted events by default +WHERE + (@entity_ids::int[] = '{}' OR entity_id = ANY(@entity_ids::int[])) + AND (@entity_type::text = '' OR entity_type = @entity_type::event_entity_type) + AND (@event_type::text = '' OR event_type = @event_type::event_type) AND (@filter_deleted::boolean IS NULL OR is_deleted = @filter_deleted) -ORDER BY created_at DESC -LIMIT @limit -OFFSET @offset; +ORDER BY created_at DESC, event_id ASC +LIMIT @limit_val +OFFSET @offset_val; diff --git a/api/fixture_test.go b/api/fixture_test.go index 919e6280..0481181c 100644 --- a/api/fixture_test.go +++ b/api/fixture_test.go @@ -193,6 +193,22 @@ var ( "txhash": "0x1", "blockhash": "0x2", } + + eventBaseRow = map[string]any{ + "txhash": "0x1", + "blockhash": "0x2", + "blocknumber": 101, + "event_id": nil, + "entity_type": nil, + "user_id": nil, + "entity_id": nil, + "event_type": nil, + "end_date": time.Now().Add(time.Hour * 24 * 30), + "is_deleted": false, + "created_at": time.Now(), + "updated_at": time.Now(), + "event_data": nil, + } ) func insertFixtures(table string, baseRow map[string]any, csvFile string) { diff --git a/api/server.go b/api/server.go index b6ecee0b..9ddc1013 100644 --- a/api/server.go +++ b/api/server.go @@ -258,9 +258,9 @@ func NewApiServer(config config.Config) *ApiServer { // Events g.Get("/events/unclaimed_id", app.v1EventsUnclaimedId) - // g.Get("/events", app.v1Events) - // g.Get("/events/all", app.v1Events) - // g.Get("/events/entity", app.v1Event) + g.Get("/events", app.v1Events) + g.Get("/events/all", app.v1Events) + g.Get("/events/entity", app.v1Events) } app.Static("/", "./static") diff --git a/api/server_test.go b/api/server_test.go index b2eaed1d..a4db29f6 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -83,6 +83,7 @@ func TestMain(m *testing.M) { insertFixtures("grants", grantBaseRow, "testdata/grants_fixtures.csv") insertFixtures("comments", commentBaseRow, "testdata/comment_fixtures.csv") insertFixtures("comment_threads", map[string]any{}, "testdata/comment_thread_fixtures.csv") + insertFixtures("events", eventBaseRow, "testdata/event_fixtures.csv") // index to es / os diff --git a/api/testdata/event_fixtures.csv b/api/testdata/event_fixtures.csv new file mode 100644 index 00000000..4d9ab7d2 --- /dev/null +++ b/api/testdata/event_fixtures.csv @@ -0,0 +1,7 @@ +event_id,entity_type,user_id,entity_id,event_type,is_deleted +1,track,200,100,remix_contest,f +2,track,200,100,live_event,f +3,track,200,100,remix_contest,t +4,track,200,101,remix_contest,f +5,track,200,101,live_event,f +6,track,201,102,remix_contest,f diff --git a/api/testdata/user_fixtures.csv b/api/testdata/user_fixtures.csv index e9e0c32a..31068425 100644 --- a/api/testdata/user_fixtures.csv +++ b/api/testdata/user_fixtures.csv @@ -11,3 +11,5 @@ user_id,handle,handle_lc,is_deactivated,wallet,playlist_library 100,authtest1,authtest1,f,0x681c616ae836ceca1effe00bd07f2fdbf9a082bc, 101,authtest2,authtest2,f,0xc451c1f8943b575158310552b41230c61844a1c1, 102,authtest3,authtest3,f,0x5f1a372b28956c8363f8bc3a231a6e9e1186ead8, +200,eventsuser,eventsuser,f,0xffffffffff, +201,eventsuser2,eventsuser2,f,0xffffffffff, \ No newline at end of file diff --git a/api/v1_events.go b/api/v1_events.go new file mode 100644 index 00000000..a797ada9 --- /dev/null +++ b/api/v1_events.go @@ -0,0 +1,44 @@ +package api + +import ( + "bridgerton.audius.co/api/dbv1" + "bridgerton.audius.co/trashid" + "github.com/gofiber/fiber/v2" +) + +func (app *ApiServer) v1Events(c *fiber.Ctx) error { + limit := c.QueryInt("limit", 25) + offset := c.QueryInt("offset", 0) + eventType := c.Query("event_type", "") + entityType := c.Query("entity_type", "") + filterDeleted := c.QueryBool("filter_deleted", true) + entityIDs := queryMutli(c, "entity_id") + + entityIds := []int32{} + for _, id := range entityIDs { + if id, err := trashid.DecodeHashId(id); err == nil { + entityIds = append(entityIds, int32(id)) + } + } + + recentEvents, err := app.queries.GetEvents(c.Context(), dbv1.GetEventsParams{ + EntityIds: entityIds, + EventType: eventType, + EntityType: entityType, + LimitVal: int32(limit), + OffsetVal: int32(offset), + FilterDeleted: !filterDeleted, + }) + if err != nil { + return err + } + + data := []dbv1.FullEvent{} + for _, event := range recentEvents { + data = append(data, app.queries.ToFullEvent(event)) + } + + return c.JSON(fiber.Map{ + "data": data, + }) +} diff --git a/api/v1_events_test.go b/api/v1_events_test.go new file mode 100644 index 00000000..189ac241 --- /dev/null +++ b/api/v1_events_test.go @@ -0,0 +1,53 @@ +package api + +import ( + "testing" + + "bridgerton.audius.co/api/dbv1" + "bridgerton.audius.co/trashid" + "github.com/stretchr/testify/assert" +) + +func TestGetEvents(t *testing.T) { + var eventsResponse struct { + Data []dbv1.FullEvent + } + + status, body := testGet(t, "/v1/events", &eventsResponse) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]string{ + "data.0.event_id": trashid.MustEncodeHashID(1), + "data.0.entity_id": trashid.MustEncodeHashID(100), + + "data.1.event_id": trashid.MustEncodeHashID(2), + "data.1.entity_id": trashid.MustEncodeHashID(100), + + "data.2.event_id": trashid.MustEncodeHashID(4), + "data.2.entity_id": trashid.MustEncodeHashID(101), + + "data.3.event_id": trashid.MustEncodeHashID(5), + "data.3.entity_id": trashid.MustEncodeHashID(101), + + "data.4.event_id": trashid.MustEncodeHashID(6), + "data.4.entity_id": trashid.MustEncodeHashID(102), + }) +} + +func TestGetEventsEntity(t *testing.T) { + var eventsResponse struct { + Data []dbv1.FullEvent + } + + status, body := testGet( + t, + "/v1/events/entity?entity_id="+trashid.MustEncodeHashID(102), + &eventsResponse, + ) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]string{ + "data.0.event_id": trashid.MustEncodeHashID(6), + "data.0.entity_id": trashid.MustEncodeHashID(102), + }) +} diff --git a/sqlc.yaml b/sqlc.yaml index 3fd38e37..47c9d758 100644 --- a/sqlc.yaml +++ b/sqlc.yaml @@ -90,6 +90,11 @@ sql: type: "AccessGate" pointer: true + - column: "events.event_data" + go_type: + type: "EventData" + pointer: true + - column: "playlists.stream_conditions" go_type: type: "AccessGate" diff --git a/static/apidiff.html b/static/apidiff.html index 89fc597c..96ef81c2 100644 --- a/static/apidiff.html +++ b/static/apidiff.html @@ -71,6 +71,9 @@ "/v1/full/tracks/449Gz30/comments?limit=15&offset=0&sort_method=top&user_id=197005", "/v1/full/tracks/449Gz30/comments?limit=15&offset=0&sort_method=newest&user_id=197005", "/v1/full/users/7eP5n/comments?limit=15&offset=0&user_id=197005", + "/v1/events?event_type=remix_contest", // Note current API does not order this deterministically + "/v1/events/all", + "/v1/events/entity?entity_id=YmozAJ7", ]; const html = (strings, ...values) => String.raw({ raw: strings }, ...values);