diff --git a/src/modules/creators/creators.limit.utils.ts b/src/modules/creators/creators.limit.utils.ts new file mode 100644 index 0000000..2f0861f --- /dev/null +++ b/src/modules/creators/creators.limit.utils.ts @@ -0,0 +1,10 @@ +import { DEFAULT_PAGE_SIZE } from '../../constants/pagination.constants'; + +/** + * Resolve list limit for public creator list endpoints. + * + * Returns the shared default page size when the incoming page size is omitted. + */ +export function resolveCreatorListLimit(pageSize?: number): number { + return pageSize ?? DEFAULT_PAGE_SIZE; +} diff --git a/src/modules/creators/creators.schemas.ts b/src/modules/creators/creators.schemas.ts index 1ef9286..e14e4f0 100644 --- a/src/modules/creators/creators.schemas.ts +++ b/src/modules/creators/creators.schemas.ts @@ -1,3 +1,4 @@ +// src/modules/creators/creators.schemas.ts import { z } from 'zod'; import { creatorListSortDirectionQueryParam } from './creators.sort-direction.parse'; import { creatorListIncludeQueryParam } from './creators.include.parse'; @@ -12,6 +13,7 @@ import { CREATOR_LIST_SORT_FIELDS, DEFAULT_CREATOR_LIST_SORT, } from '../../constants/creator-list-sort.constants'; +import { normalizeCreatorListSearchTerm } from './creators.search-term.utils'; /** * Validation schema for creator list query parameters. @@ -39,7 +41,9 @@ export const CreatorListQuerySchema = z.object({ // Sorting sort: withCreatorListQueryStringNormalization( - z.enum(CREATOR_LIST_SORT_FIELDS).optional().default(DEFAULT_CREATOR_LIST_SORT) + z.enum(CREATOR_LIST_SORT_FIELDS) + .optional() + .default(DEFAULT_CREATOR_LIST_SORT) ), order: creatorListSortDirectionQueryParam(), include: creatorListIncludeQueryParam(), @@ -54,7 +58,12 @@ export const CreatorListQuerySchema = z.object({ return val === 'true'; }) ), - search: withCreatorListQueryStringNormalization(z.string().optional()), + search: withCreatorListQueryStringNormalization( + z + .string() + .optional() + .transform(val => normalizeCreatorListSearchTerm(val)) + ), }); export type CreatorListQueryType = z.infer; diff --git a/src/modules/creators/creators.search-term.utils.ts b/src/modules/creators/creators.search-term.utils.ts new file mode 100644 index 0000000..0c0f34f --- /dev/null +++ b/src/modules/creators/creators.search-term.utils.ts @@ -0,0 +1,20 @@ +/** + * Normalize free-text creator list search terms before filtering. + * + * Scope is intentionally narrow and reusable: + * - Accepts `string | null | undefined` + * - Trims leading/trailing whitespace + * - Collapses internal whitespace to single spaces + * - Returns `undefined` for empty/whitespace-only values + */ +export function normalizeCreatorListSearchTerm( + term: string | null | undefined +): string | undefined { + if (typeof term !== 'string') { + return undefined; + } + + const normalized = term.trim().replace(/\s+/g, ' '); + return normalized === '' ? undefined : normalized; +} + diff --git a/src/modules/creators/creators.utils.ts b/src/modules/creators/creators.utils.ts index 9434588..9dca020 100644 --- a/src/modules/creators/creators.utils.ts +++ b/src/modules/creators/creators.utils.ts @@ -4,6 +4,7 @@ import { CreatorListQueryType } from './creators.schemas'; import { mapCreatorListSort } from './creators.sort'; import { serializeCreatorListResponse, CreatorListResponse } from './creators.serializers'; import { buildOffsetPaginationMeta } from '../../utils/pagination.utils'; +import { normalizeCreatorListSearchTerm } from './creators.search-term.utils'; type CreatorListWhere = { isVerified?: boolean; @@ -31,10 +32,12 @@ export async function fetchCreatorList( where.isVerified = verified; } - if (search) { + const normalizedSearch = normalizeCreatorListSearchTerm(search); + + if (normalizedSearch) { where.OR = [ - { handle: { contains: search, mode: 'insensitive' } }, - { displayName: { contains: search, mode: 'insensitive' } }, + { handle: { contains: normalizedSearch, mode: 'insensitive' } }, + { displayName: { contains: normalizedSearch, mode: 'insensitive' } }, ]; }