mcp-quiz-server
Version:
🧠AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.
152 lines (151 loc) • 5.11 kB
JavaScript
"use strict";
/**
* @fileoverview List Quizzes Query - Clean Architecture Application Layer
* @version 1.0.0
* @since 2025-07-30
* @module ListQuizzesQuery
* @description Query for listing quizzes with filtering and pagination
*
* @architecture
* Layer: Application (Query)
* Pattern: Query Pattern + Pagination
* Dependencies: Domain value objects
*
* @relationships
* USED_BY:
* - ListQuizzesQueryHandler (Application Layer)
* - MCP list-quizzes tool (Infrastructure)
* - HTTP list endpoints (Infrastructure)
*
* @contributors Claude Code Agent
* @testCoverage Query validation tests, integration tests
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ListQuizzesQuery = void 0;
/**
* List Quizzes Query
*
* @description Represents a request to list quizzes with optional filtering,
* pagination, and permission checking.
*
* @example
* ```typescript
* const query = new ListQuizzesQuery({
* limit: 10,
* category: 'math',
* difficulty: 'medium',
* includeQuestions: false
* });
* ```
*
* @since 2025-07-30
* @author Claude Code Agent
*/
class ListQuizzesQuery {
constructor(data = {}) {
var _a;
// Validate and set pagination
this.limit = Math.min(Math.max(data.limit || 10, 1), 100); // Limit between 1 and 100
this.offset = Math.max(data.offset || 0, 0); // Non-negative offset
// Set filtering options
this.category = data.category;
this.difficulty = data.difficulty;
this.isActive = data.isActive !== false; // Default to true (only active quizzes)
this.searchTerm = (_a = data.searchTerm) === null || _a === void 0 ? void 0 : _a.trim();
// Set inclusion options
this.includeQuestions = data.includeQuestions === true;
this.includeStatistics = data.includeStatistics === true;
// Set sorting options
this.sortBy = data.sortBy || 'createdAt';
this.sortOrder = data.sortOrder || 'desc';
// Set user context
this.userId = data.userId;
this.metadata = {
...data.metadata,
timestamp: new Date().toISOString(),
};
// Validate sort options
this.validateSortOptions();
}
/**
* Validate sorting options
*/
validateSortOptions() {
const validSortFields = ['title', 'createdAt', 'updatedAt', 'questionCount', 'difficulty'];
const validSortOrders = ['asc', 'desc'];
if (!validSortFields.includes(this.sortBy)) {
throw new Error(`Invalid sortBy field: ${this.sortBy}. Must be one of: ${validSortFields.join(', ')}`);
}
if (!validSortOrders.includes(this.sortOrder)) {
throw new Error(`Invalid sortOrder: ${this.sortOrder}. Must be 'asc' or 'desc'`);
}
if (this.difficulty && !['easy', 'medium', 'hard', 'expert'].includes(this.difficulty)) {
throw new Error(`Invalid difficulty: ${this.difficulty}. Must be one of: easy, medium, hard, expert`);
}
}
/**
* Check if this is a search query
*/
isSearchQuery() {
return !!this.searchTerm && this.searchTerm.length > 0;
}
/**
* Check if this query has filters applied
*/
hasFilters() {
return !!(this.category || this.difficulty || this.searchTerm || this.isActive === false);
}
/**
* Get pagination info for response metadata
*/
getPaginationInfo() {
return {
limit: this.limit,
offset: this.offset,
page: Math.floor(this.offset / this.limit) + 1,
pageSize: this.limit,
};
}
/**
* Convert to repository search criteria
*/
toSearchCriteria() {
return {
category: this.category,
difficulty: this.difficulty,
isActive: this.isActive,
titleContains: this.searchTerm,
hasQuestions: true, // Only return quizzes with questions
};
}
/**
* Convert to repository search options
*/
toSearchOptions() {
return {
limit: this.limit,
offset: this.offset,
sortBy: this.sortBy,
sortOrder: this.sortOrder,
includeQuestions: this.includeQuestions,
includeResults: this.includeStatistics,
};
}
/**
* Convert to string representation for logging
*/
toString() {
const filters = [];
if (this.category)
filters.push(`category=${this.category}`);
if (this.difficulty)
filters.push(`difficulty=${this.difficulty}`);
if (this.searchTerm)
filters.push(`search="${this.searchTerm}"`);
if (this.isActive === false)
filters.push('includeInactive=true');
const filterStr = filters.length > 0 ? ` with filters: ${filters.join(', ')}` : '';
return `ListQuizzesQuery(limit=${this.limit}, offset=${this.offset}, sortBy=${this.sortBy}${filterStr})`;
}
}
exports.ListQuizzesQuery = ListQuizzesQuery;