import { Injectable } from '@nestjs/common'; import { TrackerStreamsRepository } from '@task-stream/api/tracker/application'; import { CommentAddedEvent, IssueCreatedEvent, IssueLinkedEvent, ReleaseCreatedEvent, } from '@task-stream/api/tracker/domain'; import { DataSource } from 'typeorm'; /** Reads the event store directly: which streams hang off a project or a ticket. */ @Injectable() export class PostgresTrackerStreamsRepository extends TrackerStreamsRepository { constructor(private readonly dataSource: DataSource) { super(); } issueIdsOfProject(projectId: string): Promise { return this.streams( IssueCreatedEvent.name, `data->>'projectId'`, projectId, ); } releaseIdsOfProject(projectId: string): Promise { return this.streams( ReleaseCreatedEvent.name, `data->>'projectId'`, projectId, ); } commentIdsOfIssue(issueId: string): Promise { return this.streams( CommentAddedEvent.name, `data->'comment'->>'issueId'`, issueId, ); } issueIdsLinkingTo(issueId: string): Promise { return this.streams( IssueLinkedEvent.name, `data->'link'->>'targetIssueId'`, issueId, ); } /** `field` is one of the fixed JSON paths above, never user input. */ private async streams( type: string, field: string, value: string, ): Promise { const rows: { stream_id: string }[] = await this.dataSource.query( `SELECT DISTINCT stream_id FROM events WHERE type = $1 AND ${field} = $2`, [type, value], ); return rows.map((row) => row.stream_id); } }