feat(pagination): add generic typed pagination with ordering to all list endpoints

- add PaginationQueryDto<TOrderBy> generic with orderBy and orderDir fields
- add SessionOrderBy, EnvironmentOrderBy, ScenarioOrderBy type aliases
- update session, environment, scenario services and controllers to use typed pagination
- update MCP list_sessions, list_environments, list_scenarios tools to expose orderBy/orderDir
- update tests for all list endpoints to cover page, limit, ordering, and invalid param rejection
This commit is contained in:
2026-04-07 17:54:23 +03:00
parent d9cdb64ee2
commit 36f8b8c0ca
16 changed files with 337 additions and 81 deletions
+8 -20
View File
@@ -1,6 +1,8 @@
import { Controller, Delete, Get, NotFoundException, Param, ParseIntPipe } from '@nestjs/common';
import { Controller, Delete, Get, NotFoundException, Param, ParseIntPipe, Query } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { SessionService } from './session.service';
import { PaginationQueryDto } from '../common/dto/pagination.dto';
import { SessionOrderBy } from './session.service';
@ApiTags('sessions')
@Controller('sessions')
@@ -8,24 +10,10 @@ export class SessionController {
constructor(private readonly sessionService: SessionService) {}
@Get()
@ApiOperation({ summary: 'List all stored sessions' })
@ApiResponse({
status: 200,
description: 'Array of sessions',
schema: {
type: 'array',
items: {
properties: {
id: { type: 'number' },
sessionName: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
},
},
},
})
findAll() {
return this.sessionService.findAll();
@ApiOperation({ summary: 'List all stored sessions (paginated)' })
@ApiResponse({ status: 200, description: 'Paginated sessions' })
findAll(@Query() query: PaginationQueryDto<SessionOrderBy>) {
return this.sessionService.findAll(query);
}
@Delete(':id')
@@ -34,7 +22,7 @@ export class SessionController {
@ApiResponse({ status: 404, description: 'Session not found' })
async remove(@Param('id', ParseIntPipe) id: number): Promise<void> {
const sessions = await this.sessionService.findAll();
if (!sessions.find(s => s.id === id)) {
if (!sessions.data.find(s => s.id === id)) {
throw new NotFoundException(`Session ${id} not found`);
}
await this.sessionService.remove(id);