Skip to content

Commit 159e97c

Browse files
authored
Merge pull request #83 from Johnpii1/issue-4
Add creator list search term normalizer
2 parents cc02f72 + ed73ac0 commit 159e97c

2 files changed

Lines changed: 90 additions & 105 deletions

File tree

Lines changed: 49 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,63 @@
11
// src/modules/creator/creator.controller.ts
2-
import { Request, Response } from 'express';
3-
import { z } from 'zod';
2+
import { RequestHandler } from 'express';
3+
4+
// API response helpers
45
import {
5-
sendSuccess,
6-
sendError,
7-
sendValidationError,
8-
ErrorCode,
6+
sendSuccess,
7+
sendError,
8+
sendValidationError,
9+
ErrorCode,
910
} from '../../utils/api-response.utils';
11+
12+
// Creator service and utilities
1013
import { getPaginatedCreators } from './creator.service';
1114
import { parseCreatorSortOptions } from './creator.utils';
12-
import { safeIntParam } from '../../utils/query.utils';
1315
import { parsePublicQuery } from '../../utils/public-query-parse.utils';
1416
import { wrapPublicCreatorListResponse } from '../creators/public-creator-list-envelope.utils';
1517
import { buildCreatorListRequestContext } from '../creators/creator-list-context.utils';
1618
import { normalizeCreatorListPage } from './creator-list-page.guard';
17-
import {
18-
MIN_PAGE_SIZE,
19-
MAX_PAGE_SIZE,
20-
} from '../../constants/pagination.constants';
21-
import { PUBLIC_PAGE_PAGINATION_DEFAULTS } from '../../utils/public-list-query-defaults';
2219

23-
const LegacyCreatorQuerySchema = z.object({
24-
page: safeIntParam({
25-
defaultValue: PUBLIC_PAGE_PAGINATION_DEFAULTS.page,
26-
min: MIN_PAGE_SIZE,
27-
max: Number.MAX_SAFE_INTEGER,
28-
label: 'Page',
29-
}),
30-
limit: safeIntParam({
31-
defaultValue: PUBLIC_PAGE_PAGINATION_DEFAULTS.limit,
32-
min: MIN_PAGE_SIZE,
33-
max: MAX_PAGE_SIZE,
34-
label: 'Limit',
35-
}),
36-
sortBy: z.string().optional(),
37-
sortOrder: z.string().optional(),
38-
});
20+
// Legacy query schema
21+
import { LegacyCreatorQuerySchema } from '../creators/creators.schemas';
22+
23+
// Typed Express handler
24+
export const listCreators: RequestHandler = async (req, res) => {
25+
try {
26+
// Build request context
27+
const ctx = buildCreatorListRequestContext(req);
28+
29+
// Parse query using legacy schema
30+
const parsed = parsePublicQuery(LegacyCreatorQuerySchema, ctx.query);
31+
32+
if (!parsed.ok) {
33+
return sendValidationError(res, 'Invalid query parameters', parsed.details);
34+
}
35+
36+
// Destructure using schema fields
37+
const { offset, limit, sort, order: sortOrder } = parsed.data;
3938

40-
export async function listCreators(req: Request, res: Response) {
41-
try {
42-
const ctx = buildCreatorListRequestContext(req);
43-
const parsed = parsePublicQuery(LegacyCreatorQuerySchema, ctx.query);
44-
if (!parsed.ok) {
45-
return sendValidationError(
46-
res,
47-
'Invalid query parameters',
48-
parsed.details
49-
);
50-
}
51-
const { limit, sortBy, sortOrder } = parsed.data;
52-
const page = normalizeCreatorListPage(parsed.data.page);
39+
// Convert offset to page number
40+
const page = normalizeCreatorListPage(offset);
5341

54-
const sort = parseCreatorSortOptions(sortBy, sortOrder);
42+
// Build sort options
43+
const sortOptions = parseCreatorSortOptions(sort, sortOrder);
5544

56-
const { creators, meta } = await getPaginatedCreators({
57-
page,
58-
limit,
59-
sort,
60-
});
45+
// Fetch paginated creators
46+
const { creators, meta } = await getPaginatedCreators({
47+
page,
48+
limit,
49+
sort: sortOptions,
50+
});
6151

62-
return sendSuccess(
63-
res,
64-
wrapPublicCreatorListResponse(creators, meta),
65-
200,
66-
'Creators retrieved successfully'
67-
);
68-
} catch (error) {
69-
console.error('Error listing creators:', error);
70-
return sendError(
71-
res,
72-
500,
73-
ErrorCode.INTERNAL_ERROR,
74-
'Failed to retrieve creators'
75-
);
76-
}
77-
}
52+
// Send success response
53+
return sendSuccess(
54+
res,
55+
wrapPublicCreatorListResponse(creators, meta),
56+
200,
57+
'Creators retrieved successfully'
58+
);
59+
} catch (error) {
60+
console.error('Error listing creators:', error);
61+
return sendError(res, 500, ErrorCode.INTERNAL_ERROR, 'Failed to retrieve creators');
62+
}
63+
};
Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
// src/modules/creators/creators.schemas.ts
21
import { z } from 'zod';
32
import { creatorListSortDirectionQueryParam } from './creators.sort-direction.parse';
43
import { creatorListIncludeQueryParam } from './creators.include.parse';
54
import { withCreatorListQueryStringNormalization } from './creators.query-string.utils';
65
import { safeIntParam } from '../../utils/query.utils';
76
import {
8-
MIN_PAGE_SIZE,
9-
MAX_PAGE_SIZE,
7+
MIN_PAGE_SIZE,
8+
MAX_PAGE_SIZE,
109
} from '../../constants/pagination.constants';
1110
import { PUBLIC_OFFSET_PAGINATION_DEFAULTS } from '../../utils/public-list-query-defaults';
11+
1212
import {
13-
CREATOR_LIST_SORT_FIELDS,
14-
DEFAULT_CREATOR_LIST_SORT,
13+
CREATOR_LIST_SORT_FIELDS,
14+
DEFAULT_CREATOR_LIST_SORT,
1515
} from '../../constants/creator-list-sort.constants';
16+
import { resolveCreatorListLimit } from './creators.limit.utils';
1617
import { normalizeCreatorListSearchTerm } from './creators.search-term.utils';
1718

1819
/**
@@ -25,45 +26,43 @@ import { normalizeCreatorListSearchTerm } from './creators.search-term.utils';
2526
* GET /api/v1/creators?limit=20&offset=0&sort=createdAt&order=desc&verified=true
2627
*/
2728
export const CreatorListQuerySchema = z.object({
28-
// Pagination
29-
limit: safeIntParam({
30-
defaultValue: PUBLIC_OFFSET_PAGINATION_DEFAULTS.limit,
31-
min: MIN_PAGE_SIZE,
32-
max: MAX_PAGE_SIZE,
33-
label: 'Limit',
34-
}),
35-
offset: safeIntParam({
36-
defaultValue: PUBLIC_OFFSET_PAGINATION_DEFAULTS.offset,
37-
min: 0,
38-
max: Number.MAX_SAFE_INTEGER,
39-
label: 'Offset',
40-
}),
29+
// Pagination
30+
limit: safeIntParam({
31+
defaultValue: resolveCreatorListLimit() ?? PUBLIC_OFFSET_PAGINATION_DEFAULTS.limit,
32+
min: MIN_PAGE_SIZE,
33+
max: MAX_PAGE_SIZE,
34+
label: 'Limit',
35+
}),
36+
offset: safeIntParam({
37+
defaultValue: PUBLIC_OFFSET_PAGINATION_DEFAULTS.offset,
38+
min: 0,
39+
max: Number.MAX_SAFE_INTEGER,
40+
label: 'Offset',
41+
}),
4142

42-
// Sorting
43-
sort: withCreatorListQueryStringNormalization(
44-
z.enum(CREATOR_LIST_SORT_FIELDS)
45-
.optional()
46-
.default(DEFAULT_CREATOR_LIST_SORT)
47-
),
48-
order: creatorListSortDirectionQueryParam(),
49-
include: creatorListIncludeQueryParam(),
43+
// Sorting
44+
sort: withCreatorListQueryStringNormalization(
45+
z.enum(CREATOR_LIST_SORT_FIELDS).optional().default(DEFAULT_CREATOR_LIST_SORT)
46+
),
47+
order: creatorListSortDirectionQueryParam(),
48+
include: creatorListIncludeQueryParam(),
5049

51-
// Filters
52-
verified: withCreatorListQueryStringNormalization(
53-
z
54-
.string()
55-
.optional()
56-
.transform(val => {
57-
if (val === undefined) return undefined;
58-
return val === 'true';
59-
})
60-
),
61-
search: withCreatorListQueryStringNormalization(
62-
z
63-
.string()
64-
.optional()
65-
.transform(val => normalizeCreatorListSearchTerm(val))
66-
),
50+
// Filters
51+
verified: withCreatorListQueryStringNormalization(
52+
z
53+
.string()
54+
.optional()
55+
.transform(val => (val === undefined ? undefined : val === 'true'))
56+
),
57+
search: withCreatorListQueryStringNormalization(
58+
z
59+
.string()
60+
.optional()
61+
.transform(val => normalizeCreatorListSearchTerm(val))
62+
),
6763
});
6864

65+
// Export as LegacyCreatorQuerySchema for backward compatibility
66+
export const LegacyCreatorQuerySchema = CreatorListQuerySchema;
67+
6968
export type CreatorListQueryType = z.infer<typeof CreatorListQuerySchema>;

0 commit comments

Comments
 (0)