* Retrieve channels in a paginated format with optional filtering/sorting * @param {Object} options - Pagination and filtering options * @param {number|string} [options.page=1] - Page number (1-indexed) * @param {number|string} [options.pageSize=50] - Number of items per page * @param {s
({
page = 1,
pageSize = 50,
searchTerm = '',
sortBy = 'name',
sortOrder = 'asc',
subFolder = null,
} = {})
| 1049 | * @returns {Promise<{channels: Array, total: number, page: number, pageSize: number, totalPages: number}>} |
| 1050 | */ |
| 1051 | async getChannelsPaginated({ |
| 1052 | page = 1, |
| 1053 | pageSize = 50, |
| 1054 | searchTerm = '', |
| 1055 | sortBy = 'name', |
| 1056 | sortOrder = 'asc', |
| 1057 | subFolder = null, |
| 1058 | } = {}) { |
| 1059 | const parsedPage = parseInt(page, 10); |
| 1060 | const parsedPageSize = parseInt(pageSize, 10); |
| 1061 | const safePage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1; |
| 1062 | const safePageSize = Number.isFinite(parsedPageSize) |
| 1063 | ? Math.min(Math.max(parsedPageSize, 1), 100) |
| 1064 | : 50; |
| 1065 | const offset = (safePage - 1) * safePageSize; |
| 1066 | |
| 1067 | const whereClause = { enabled: true }; |
| 1068 | const normalizedSearch = typeof searchTerm === 'string' ? searchTerm.trim().toLowerCase() : ''; |
| 1069 | if (normalizedSearch) { |
| 1070 | const escapedSearch = normalizedSearch.replace(/[\\%_]/g, '\\$&'); |
| 1071 | const likeValue = `%${escapedSearch}%`; |
| 1072 | whereClause[Op.or] = [ |
| 1073 | where(fn('LOWER', col('uploader')), { [Op.like]: likeValue }), |
| 1074 | where(fn('LOWER', col('url')), { [Op.like]: likeValue }), |
| 1075 | ]; |
| 1076 | } |
| 1077 | |
| 1078 | const normalizedSubFolder = typeof subFolder === 'string' ? subFolder.trim() : ''; |
| 1079 | if (normalizedSubFolder) { |
| 1080 | if (normalizedSubFolder === SUB_FOLDER_DEFAULT_KEY) { |
| 1081 | whereClause.sub_folder = { |
| 1082 | [Op.or]: [null, ''], |
| 1083 | }; |
| 1084 | } else { |
| 1085 | whereClause.sub_folder = normalizedSubFolder; |
| 1086 | } |
| 1087 | } |
| 1088 | |
| 1089 | const sortMap = { |
| 1090 | name: 'uploader', |
| 1091 | uploader: 'uploader', |
| 1092 | createdat: 'createdAt', |
| 1093 | }; |
| 1094 | const normalizedSortKey = typeof sortBy === 'string' ? sortBy.toLowerCase() : 'name'; |
| 1095 | const sortColumn = sortMap[normalizedSortKey] || 'uploader'; |
| 1096 | const direction = typeof sortOrder === 'string' && sortOrder.toLowerCase() === 'desc' ? 'DESC' : 'ASC'; |
| 1097 | |
| 1098 | try { |
| 1099 | const { rows, count } = await Channel.findAndCountAll({ |
| 1100 | where: whereClause, |
| 1101 | limit: safePageSize, |
| 1102 | offset, |
| 1103 | order: [[sortColumn, direction]], |
| 1104 | }); |
| 1105 | |
| 1106 | const distinctSubFolders = await Channel.findAll({ |
| 1107 | attributes: [[fn('DISTINCT', col('sub_folder')), 'sub_folder']], |
| 1108 | where: { enabled: true }, |
no test coverage detected