wagerkit / backend /src /markets /markets.controller.ts
saadrizvi09
added search
8626b2e
import {
Controller,
Get,
Post,
Param,
Query,
Body,
Res,
Inject,
Optional,
NotFoundException,
} from '@nestjs/common';
import { Response } from 'express';
import { MarketsService } from './markets.service';
import { MarketCacheService } from './market-cache.service';
@Controller('markets')
export class MarketsController {
private readonly marketQueue: any;
constructor(
private readonly marketsService: MarketsService,
private readonly cacheService: MarketCacheService,
@Optional() @Inject('BullQueue_market-processing') marketQueue?: any,
) {
this.marketQueue = marketQueue || null;
}
@Get()
getMarkets(@Query('q') query?: string) {
if (query && query.trim().length > 0) {
return this.marketsService.searchMarkets(query);
}
const markets = this.marketsService.getMarkets();
// Enrich with processing status
return markets.map((m) => {
const cached = this.cacheService.get(m.slug);
return {
...m,
processingStatus: cached?.status || 'unknown',
};
});
}
@Post('search')
searchMarket(@Body('query') query: string) {
if (!query || query.trim().length < 2) {
return { error: 'Query must be at least 2 characters' };
}
const detail = this.marketsService.searchOrCreateMarket(query.trim());
return detail;
}
@Get('jobs/status')
getJobsStatus() {
const all = this.cacheService.getAll();
return {
markets: all.map((c) => ({
slug: c.slug,
status: c.status,
updatedAt: c.updatedAt,
error: c.error,
})),
summary: {
total: all.length,
ready: all.filter((c) => c.status === 'ready').length,
processing: all.filter((c) => c.status === 'processing').length,
pending: all.filter((c) => c.status === 'pending').length,
error: all.filter((c) => c.status === 'error').length,
},
};
}
@Post(':slug/refresh')
async refreshMarket(@Param('slug') slug: string) {
const market = this.marketsService.getMarkets().find((m) => m.slug === slug);
if (!market) {
throw new NotFoundException('Market not found');
}
if (this.marketQueue) {
this.cacheService.setStatus(slug, 'pending');
await this.marketQueue.add(
'process-market',
{ slug },
{ removeOnComplete: 100, removeOnFail: 50 },
);
return { message: 'Market refresh queued', slug, status: 'pending' };
}
return { message: 'Market data refreshed (no queue)', slug, status: 'ready' };
}
@Get(':slug')
getMarketDetail(@Param('slug') slug: string) {
// Return cached data if available (processed by BullMQ worker)
const cached = this.cacheService.get(slug);
if (cached?.status === 'ready' && cached.data) {
return {
...cached.data,
fromCache: true,
processingStatus: 'ready',
};
}
// Try to get the market detail (works for both hardcoded + dynamic)
const market = this.marketsService.getMarketDetail(slug);
if (!market) {
throw new NotFoundException('Market not found');
}
return {
...market,
fromCache: false,
processingStatus: cached?.status || 'not-queued',
};
}
@Get(':slug/export/odds-csv')
exportOddsCsv(@Param('slug') slug: string, @Res() res: Response) {
const csv = this.marketsService.getOddsHistoryCsv(slug);
if (!csv) {
throw new NotFoundException('Market not found');
}
res.setHeader('Content-Type', 'text/csv');
res.setHeader(
'Content-Disposition',
`attachment; filename=odds_history_${slug}.csv`,
);
res.send(csv);
}
@Get(':slug/export/integrity-csv')
exportIntegrityCsv(@Param('slug') slug: string, @Res() res: Response) {
const csv = this.marketsService.getIntegrityCsv(slug);
if (!csv) {
throw new NotFoundException('Market not found');
}
res.setHeader('Content-Type', 'text/csv');
res.setHeader(
'Content-Disposition',
`attachment; filename=integrity_${slug}.csv`,
);
res.send(csv);
}
@Get(':slug/export/dossier-json')
exportDossierJson(@Param('slug') slug: string) {
const dossier = this.marketsService.getDossierJson(slug);
if (!dossier) {
throw new NotFoundException('Market not found');
}
return dossier;
}
}