Implement MaterialsToDeleteDAO class with secure parameterized queries following the pattern established in Task 11 (commit 5aafb23). Features: - getMaterialsToDeleteByManagers(): Query materials_to_delete table with optional filtering by manager_names using parameterized queries - getAllMaterialsToDelete(): Wrapper to retrieve all materials without filtering Security: - Uses parameterized queries (@param0, @param1, etc.) to prevent SQL injection - Parameters passed separately from query string via executeSQLServerQuery() - Input validation for empty arrays - Comprehensive test coverage including SQL injection attempt scenarios Testing: - 11 comprehensive unit tests covering all methods and edge cases - Tests verify parameterized query pattern prevents SQL injection - All tests passing (12/12 including existing tests) Files: - src/main/dao/materials-to-delete.dao.ts: DAO implementation - tests/unit/dao/materials-to-delete.dao.test.ts: Unit tests Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
62 lines
2.1 KiB
TypeScript
62 lines
2.1 KiB
TypeScript
import { DatabaseService } from '../services/database.service';
|
|
import { LoggerService } from '../services/logger.service';
|
|
|
|
export class MaterialsToDeleteDAO {
|
|
constructor(private dbService: DatabaseService) {}
|
|
|
|
/**
|
|
* Query materials_to_delete table and return distinct material codes
|
|
* @param managerNames - Optional array of manager names to filter by. Pass null to get all materials.
|
|
* @returns Promise<string[]> - Array of distinct material codes
|
|
*/
|
|
async getMaterialsToDeleteByManagers(
|
|
managerNames: string[] | null
|
|
): Promise<string[]> {
|
|
try {
|
|
// Input validation
|
|
if (managerNames && managerNames.length === 0) {
|
|
LoggerService.warn('Empty manager names array provided, returning empty result');
|
|
return [];
|
|
}
|
|
|
|
LoggerService.info(
|
|
`Querying materials_to_delete${managerNames ? ` for ${managerNames.length} managers` : ' (all managers)'}`
|
|
);
|
|
|
|
// Build base query
|
|
let query = `
|
|
SELECT DISTINCT material_code
|
|
FROM materials_to_delete
|
|
`;
|
|
|
|
let params: string[] | undefined;
|
|
|
|
// Add WHERE clause with parameterized query if manager names provided
|
|
// SECURITY: Use parameterized queries to prevent SQL injection
|
|
if (managerNames && managerNames.length > 0) {
|
|
const placeholders = managerNames.map((_, i) => `@param${i}`).join(',');
|
|
query += ` WHERE manager_name IN (${placeholders})`;
|
|
params = managerNames;
|
|
}
|
|
|
|
// Execute query with parameters (if any)
|
|
const result = await this.dbService.executeSQLServerQuery(query, params);
|
|
const materials = result.rows.map((row: any) => row.material_code);
|
|
|
|
LoggerService.info(`Found ${materials.length} materials to delete`);
|
|
return materials;
|
|
} catch (error) {
|
|
LoggerService.error('Failed to query materials_to_delete table', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all materials from materials_to_delete table without filtering
|
|
* @returns Promise<string[]> - Array of all distinct material codes
|
|
*/
|
|
async getAllMaterialsToDelete(): Promise<string[]> {
|
|
return this.getMaterialsToDeleteByManagers(null);
|
|
}
|
|
}
|