From 515018d829adb537c5b1e838a17f15dad7c36b22 Mon Sep 17 00:00:00 2001 From: tudor <7089284+tudddorrr@users.noreply.github.com> Date: Sun, 31 Aug 2025 08:05:37 +0100 Subject: [PATCH 1/3] mass hydrate events --- src/entities/event.ts | 51 ++++++++++++++++++++++++++++++++++ src/services/player.service.ts | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/entities/event.ts b/src/entities/event.ts index d8b3b342..33298947 100644 --- a/src/entities/event.ts +++ b/src/entities/event.ts @@ -35,6 +35,57 @@ export default class Event extends ClickHouseEntity { + const playerAliasIds = Array.from(new Set(data.map((event) => event.player_alias_id))) + + const playerAliases = await em.getRepository(PlayerAlias).find({ + id: { + $in: playerAliasIds + } + }, { populate: ['player'] }) + + const playerAliasesMap = new Map() + playerAliases.forEach((alias) => playerAliasesMap.set(alias.id, alias)) + + const propsMap = new Map() + if (loadProps) { + const eventIds = data.map((event) => `'${event.id}'`).join(', ') + if (eventIds.length > 0) { + const props = await clickhouse.query({ + query: `SELECT * FROM event_props WHERE event_id IN (${eventIds})`, + format: 'JSONEachRow' + }).then((res) => res.json()) + + props.forEach((prop) => { + if (!propsMap.has(prop.event_id)) { + propsMap.set(prop.event_id, []) + } + propsMap.get(prop.event_id)!.push(new Prop(prop.prop_key, prop.prop_value)) + }) + } + } + + return data.map((eventData) => { + const playerAlias = playerAliasesMap.get(eventData.player_alias_id) + if (!playerAlias) { + return null + } + + const event = new Event() + event.construct(eventData.name, playerAlias.player.game) + event.id = eventData.id + event.playerAlias = playerAlias + event.createdAt = new Date(eventData.created_at) + event.updatedAt = new Date(eventData.updated_at) + + if (loadProps) { + event.props = propsMap.get(eventData.id) || [] + } + + return event + }).filter((event) => !!event) + } + construct(name: string, game: Game): this { this.name = name this.game = game diff --git a/src/services/player.service.ts b/src/services/player.service.ts index 9ddfdb2f..7f06ae28 100644 --- a/src/services/player.service.ts +++ b/src/services/player.service.ts @@ -348,7 +348,7 @@ export default class PlayerService extends Service { query_params: queryParams, format: 'JSONEachRow' }).then((res) => res.json()) - const events = await Promise.all(items.map((data) => new Event().hydrate(em, data, clickhouse, true))) + const events = await Event.massHydrate(em, items, clickhouse, true) const countQuery = ` SELECT count(DISTINCT events.id) AS count From a1ad415052452b90a4e4dee01d9757dcab47560b Mon Sep 17 00:00:00 2001 From: tudor <7089284+tudddorrr@users.noreply.github.com> Date: Sun, 31 Aug 2025 08:44:46 +0100 Subject: [PATCH 2/3] add props to test --- tests/services/player/events.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/services/player/events.test.ts b/tests/services/player/events.test.ts index 7aedf431..78bdf7dd 100644 --- a/tests/services/player/events.test.ts +++ b/tests/services/player/events.test.ts @@ -18,6 +18,11 @@ describe('Player service - get events', () => { values: events.map((event) => event.toInsertable()), format: 'JSONEachRow' }) + await clickhouse.insert({ + table: 'event_props', + values: events.flatMap((event) => event.getInsertableProps()), + format: 'JSONEachRow' + }) const res = await request(app) .get(`/games/${game.id}/players/${player.id}/events`) From 0ba18a28717ce3e7b935877d39b087f4ca6c7f70 Mon Sep 17 00:00:00 2001 From: tudor <7089284+tudddorrr@users.noreply.github.com> Date: Sun, 31 Aug 2025 08:51:58 +0100 Subject: [PATCH 3/3] use query_params --- src/entities/event.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/entities/event.ts b/src/entities/event.ts index 33298947..a8350cff 100644 --- a/src/entities/event.ts +++ b/src/entities/event.ts @@ -49,10 +49,11 @@ export default class Event extends ClickHouseEntity() if (loadProps) { - const eventIds = data.map((event) => `'${event.id}'`).join(', ') + const eventIds = data.map((event) => event.id) if (eventIds.length > 0) { const props = await clickhouse.query({ - query: `SELECT * FROM event_props WHERE event_id IN (${eventIds})`, + query: 'SELECT * FROM event_props WHERE event_id IN ({eventIds:Array(String)})', + query_params: { eventIds }, format: 'JSONEachRow' }).then((res) => res.json()) @@ -142,7 +143,8 @@ export default class Event extends ClickHouseEntity res.json())