From be8bb94be5741013a238177fda1cf34e92c95d0e Mon Sep 17 00:00:00 2001 From: extolkom Date: Sun, 31 May 2026 03:06:06 -1200 Subject: [PATCH] Implement fetchCreatorProfilesByIds function to retrieve creator profiles in order --- src/utils/creator-batch.utils.test.ts | 52 +++++++++++++++++++++++++++ src/utils/creator-batch.utils.ts | 39 ++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/utils/creator-batch.utils.test.ts create mode 100644 src/utils/creator-batch.utils.ts diff --git a/src/utils/creator-batch.utils.test.ts b/src/utils/creator-batch.utils.test.ts new file mode 100644 index 0000000..04a1e6c --- /dev/null +++ b/src/utils/creator-batch.utils.test.ts @@ -0,0 +1,52 @@ +import { fetchCreatorProfilesByIds, CREATOR_PROFILE_SELECT } from './creator-batch.utils'; +import { prisma } from './prisma.utils'; + +jest.mock('./prisma.utils', () => ({ + prisma: { + creatorProfile: { + findMany: jest.fn(), + }, + }, +})); + +const findMany = prisma.creatorProfile.findMany as jest.Mock; + +describe('fetchCreatorProfilesByIds', () => { + beforeEach(() => { + findMany.mockReset(); + }); + + it('returns records in the same order as the input ids and issues one query', async () => { + const ids = ['b', 'a', 'c']; + + const createdAt = new Date('2020-01-01T00:00:00.000Z'); + const updatedAt = new Date('2020-02-01T00:00:00.000Z'); + + // return records in a different order to ensure we reorder them + findMany.mockResolvedValueOnce([ + { id: 'a', userId: 'u-a', handle: 'a', displayName: 'A', bio: null, avatarUrl: null, perkSummary: null, isVerified: false, createdAt, updatedAt }, + { id: 'b', userId: 'u-b', handle: 'b', displayName: 'B', bio: null, avatarUrl: null, perkSummary: null, isVerified: true, createdAt, updatedAt }, + { id: 'c', userId: 'u-c', handle: 'c', displayName: 'C', bio: null, avatarUrl: null, perkSummary: null, isVerified: false, createdAt, updatedAt }, + ]); + + const result = await fetchCreatorProfilesByIds(ids); + + expect(findMany).toHaveBeenCalledTimes(1); + expect(findMany).toHaveBeenCalledWith({ + where: { id: { in: ids } }, + select: CREATOR_PROFILE_SELECT, + }); + + expect(result.map((r) => (r ? r.id : null))).toEqual(ids); + }); + + it('returns nulls for missing records preserving order', async () => { + const ids = ['x', 'y']; + findMany.mockResolvedValueOnce([{ id: 'y', userId: 'u-y', handle: 'y', displayName: 'Y', bio: null, avatarUrl: null, perkSummary: null, isVerified: false, createdAt: new Date(), updatedAt: new Date() }]); + + const result = await fetchCreatorProfilesByIds(ids); + + expect(findMany).toHaveBeenCalledTimes(1); + expect(result.map((r) => (r ? r.id : null))).toEqual([null, 'y']); + }); +}); diff --git a/src/utils/creator-batch.utils.ts b/src/utils/creator-batch.utils.ts new file mode 100644 index 0000000..cc81a00 --- /dev/null +++ b/src/utils/creator-batch.utils.ts @@ -0,0 +1,39 @@ +import { prisma } from './prisma.utils'; +import { CreatorProfile } from '../types/profile.types'; + +// Fields matching the `CreatorProfile` type stored in the DB +const CREATOR_PROFILE_SELECT = { + id: true, + userId: true, + handle: true, + displayName: true, + bio: true, + avatarUrl: true, + perkSummary: true, + isVerified: true, + createdAt: true, + updatedAt: true, +}; + +/** + * Fetch multiple creator profiles in a single query and return results in the + * same order as the provided `ids` array. Missing records are returned as + * `null` in their input position. + */ +export async function fetchCreatorProfilesByIds( + ids: string[] +): Promise<(CreatorProfile | null)[]> { + if (!ids || ids.length === 0) return []; + + const records = await prisma.creatorProfile.findMany({ + where: { id: { in: ids } }, + select: CREATOR_PROFILE_SELECT, + }); + + const map = new Map(); + records.forEach((r) => map.set(r.id, r as CreatorProfile)); + + return ids.map((id) => map.get(id) ?? null); +} + +export { CREATOR_PROFILE_SELECT };