Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/utils/creator-batch.utils.test.ts
Original file line number Diff line number Diff line change
@@ -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']);
});
});
39 changes: 39 additions & 0 deletions src/utils/creator-batch.utils.ts
Original file line number Diff line number Diff line change
@@ -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<string, CreatorProfile>();
records.forEach((r) => map.set(r.id, r as CreatorProfile));

return ids.map((id) => map.get(id) ?? null);
}

export { CREATOR_PROFILE_SELECT };
Loading