Skip to content

Commit a3ab154

Browse files
committed
feat: enhance ChannelController to support paginated responses and update pagination helper
1 parent 209ff8f commit a3ab154

File tree

2 files changed

+61
-39
lines changed

2 files changed

+61
-39
lines changed

src/controllers/channel.ts

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,32 @@ import { channelGetManyRelations, channelGetOneRelations, Channel, ChannelServic
77
subChannelGetManyRelations} from 'podverse-orm';
88
import { handleReturnDataOrNotFound } from '@api/controllers/helpers/data';
99
import { handleGenericErrorResponse } from '@api/controllers/helpers/error';
10-
import { getPaginationParams } from '@api/controllers/helpers/pagination';
10+
import { getPaginationParams, PaginatedData } from '@api/controllers/helpers/pagination';
1111
import { validateParamsObject, validateQueryObject } from '@api/lib/validation';
1212
import { getCategoryEnumValue, CATEGORY_MAPPING_KEYS, QUERY_PARAMS_CHANNELS_SORT_VALUES,
13-
QUERY_PARAMS_STATS_RANGE_VALUES } from 'podverse-helpers';
13+
QUERY_PARAMS_STATS_RANGE_VALUES, ApiListResponse } from 'podverse-helpers';
1414
import { ensureAuthenticated } from '@api/lib/auth';
1515

16+
interface SubscribedParams {
17+
account_id: number;
18+
sort?: string;
19+
range?: string;
20+
offset: number;
21+
limit: number;
22+
sendResponse: (data: PaginatedData<Channel>) => void;
23+
}
24+
25+
interface TopSortParams {
26+
range?: string;
27+
offset: number;
28+
limit: number;
29+
sendResponse: (data: PaginatedData<Channel>) => void;
30+
}
31+
32+
type ChannelWhere = FindOptionsWhere<Channel>;
33+
type ChannelOrder = FindOptionsOrder<Channel>;
34+
type AccountFollowingChannelOrder = FindOptionsOrder<AccountFollowingChannel>;
35+
1636
const getByIdOrIdTextSchema = Joi.object({
1737
idOrIdText: Joi.string().required()
1838
});
@@ -60,7 +80,13 @@ export class ChannelController {
6080
try {
6181
const { page, limit, offset } = getPaginationParams(req);
6282
const { range } = req.query as { range?: string };
63-
const sendResponse = (channels: Channel[]) => res.json({ data: channels, meta: { page } });
83+
const sendResponse = (data: PaginatedData<Channel>) => {
84+
const response: ApiListResponse<Channel> = {
85+
data: data.results,
86+
meta: { page, count: data.count, limit }
87+
};
88+
res.json(response);
89+
};
6490
await ChannelController.handleTopSort({ range, offset, limit, sendResponse });
6591
} catch (error) {
6692
handleGenericErrorResponse(res, error);
@@ -75,15 +101,22 @@ export class ChannelController {
75101
const { category, sort } = req.query as { category?: string; sort?: string };
76102
const order = ChannelController.getChannelOrder(sort);
77103
const where = ChannelController.buildChannelWhere(category as string);
78-
const sendResponse = (channels: Channel[]) => res.json({ data: channels, meta: { page } });
79104
const channels = await ChannelController.channelService.getMany({
80105
skip: offset,
81106
take: limit,
82107
relations: channelGetManyRelations,
83108
...(where && { where }),
84109
...(order && { order }),
85110
});
86-
sendResponse(channels);
111+
112+
const sendResponse = (data: PaginatedData<Channel>) => {
113+
const response: ApiListResponse<Channel> = {
114+
data: data.results,
115+
meta: { page, count: data.count, limit }
116+
};
117+
res.json(response);
118+
};
119+
sendResponse({ results: channels, count: null });
87120
} catch (error) {
88121
handleGenericErrorResponse(res, error);
89122
}
@@ -97,7 +130,13 @@ export class ChannelController {
97130
const { page, limit, offset } = getPaginationParams(req);
98131
const { sort, range } = req.query as { sort?: string; range?: string };
99132
const account_id = req.user!.id;
100-
const sendResponse = (channels: Channel[]) => res.json({ data: channels, meta: { page } });
133+
const sendResponse = (data: PaginatedData<Channel>) => {
134+
const response: ApiListResponse<Channel> = {
135+
data: data.results,
136+
meta: { page, count: data.count, limit }
137+
};
138+
res.json(response);
139+
};
101140
await ChannelController.handleSubscribed({ account_id, sort, range, offset, limit, sendResponse });
102141
} catch (error) {
103142
handleGenericErrorResponse(res, error);
@@ -110,20 +149,20 @@ export class ChannelController {
110149

111150
private static async handleSubscribed({ account_id, sort, range, offset, limit, sendResponse }: SubscribedParams) {
112151
const channel_ids = await ChannelController._getFollowedChannelIds(account_id);
113-
if (!channel_ids.length) return sendResponse([]);
152+
if (!channel_ids.length) return sendResponse({ results: [], count: 0 });
114153
if (sort === 'top') {
115154
const channels = await ChannelController._getTopSubscribedChannels(channel_ids, range, offset, limit);
116-
return sendResponse(channels);
155+
return sendResponse({ results: channels, count: channel_ids.length });
117156
}
118-
const accountFollowingChannels = await ChannelController._getSortedSubscribedChannels(account_id, sort, offset, limit);
157+
const { results: accountFollowingChannels, count } = await ChannelController._getSortedSubscribedChannels(account_id, sort, offset, limit);
119158
const channels = accountFollowingChannels.map((account_following_channel: { channel: Channel }) => account_following_channel.channel).filter(Boolean);
120-
sendResponse(channels);
159+
sendResponse({ results: channels, count });
121160
}
122161

123162
private static async _getFollowedChannelIds(account_id: number): Promise<number[]> {
124163
const accountFollowingChannelService = new AccountFollowingChannelService();
125-
const followed = await accountFollowingChannelService.getFollowedChannels(Number(account_id));
126-
return followed.map((f: { channel_id: number }) => f.channel_id);
164+
const { results } = await accountFollowingChannelService.getFollowedChannelsWithCount(Number(account_id));
165+
return results.map((f: { channel_id: number }) => f.channel_id);
127166
}
128167

129168
private static async _getTopSubscribedChannels(channel_ids: number[], range?: string, offset?: number, limit?: number): Promise<Channel[]> {
@@ -138,7 +177,7 @@ export class ChannelController {
138177
return statsResults.map((stat: { channel: Channel }) => stat.channel).filter(Boolean);
139178
}
140179

141-
private static async _getSortedSubscribedChannels(account_id: number, sort?: string, offset?: number, limit?: number): Promise<AccountFollowingChannel[]> {
180+
private static async _getSortedSubscribedChannels(account_id: number, sort?: string, offset?: number, limit?: number): Promise<{ count: number, results: AccountFollowingChannel[]}> {
142181
const accountFollowingChannelService = new AccountFollowingChannelService();
143182
const order = ChannelController.getSubscribedOrder(sort);
144183
const config: FindManyOptions<AccountFollowingChannel> = {
@@ -147,7 +186,7 @@ export class ChannelController {
147186
relations: subChannelGetManyRelations,
148187
...(order && { order }),
149188
};
150-
return await accountFollowingChannelService.getFollowedChannels(Number(account_id), config);
189+
return await accountFollowingChannelService.getFollowedChannelsWithCount(Number(account_id), config);
151190
}
152191

153192
private static async handleTopSort({ range, offset, limit, sendResponse }: TopSortParams) {
@@ -161,7 +200,7 @@ export class ChannelController {
161200

162201
const statsResults = await ChannelController.statsAggregatedChannelService.getMany([], config);
163202
const channels = statsResults.map((stat: { channel: Channel }) => stat.channel).filter(Boolean);
164-
sendResponse(channels);
203+
sendResponse({ results: channels, count: null });
165204
}
166205

167206
private static getStatsOrder(range?: string): string {
@@ -186,7 +225,7 @@ export class ChannelController {
186225
case 'oldest':
187226
return { channel: { channel_about: { last_pub_date: 'ASC' } } };
188227
case 'alphabetical':
189-
return { channel: { title: 'ASC' } };
228+
return { channel: { sortable_title: 'ASC' } };
190229
default:
191230
return undefined;
192231
}
@@ -199,7 +238,7 @@ export class ChannelController {
199238
case 'oldest':
200239
return { channel_about: { last_pub_date: 'ASC' } };
201240
case 'alphabetical':
202-
return { title: 'ASC' };
241+
return { sortable_title: 'ASC' };
203242
default:
204243
return undefined;
205244
}
@@ -213,25 +252,3 @@ export class ChannelController {
213252
return undefined;
214253
}
215254
}
216-
217-
// --- Types ---
218-
219-
interface SubscribedParams {
220-
account_id: number;
221-
sort?: string;
222-
range?: string;
223-
offset: number;
224-
limit: number;
225-
sendResponse: (channels: Channel[]) => void;
226-
}
227-
228-
interface TopSortParams {
229-
range?: string;
230-
offset: number;
231-
limit: number;
232-
sendResponse: (channels: Channel[]) => void;
233-
}
234-
235-
type ChannelWhere = FindOptionsWhere<Channel>;
236-
type ChannelOrder = FindOptionsOrder<Channel>;
237-
type AccountFollowingChannelOrder = FindOptionsOrder<AccountFollowingChannel>;

src/controllers/helpers/pagination.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ export function getPaginationParams(req: Request) {
66
const offset = (page - 1) * limit;
77
return { page, limit, offset };
88
}
9+
10+
export type PaginatedData<T> = {
11+
results: T[];
12+
count: number | null;
13+
};

0 commit comments

Comments
 (0)