Skip to content

Commit 5a0079b

Browse files
authored
feat: add previewUser details to opportunityMatches query and update schema (#3333)
1 parent 1af69b4 commit 5a0079b

3 files changed

Lines changed: 101 additions & 16 deletions

File tree

__tests__/schema/opportunity.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,75 @@ describe('query opportunityMatches', () => {
909909
});
910910
});
911911

912+
it('should include previewUser with additional information', async () => {
913+
loggedUser = '1';
914+
915+
const GET_OPPORTUNITY_MATCHES_WITH_PREVIEW_USER_QUERY = /* GraphQL */ `
916+
query GetOpportunityMatchesWithPreviewUser(
917+
$opportunityId: ID!
918+
$first: Int
919+
) {
920+
opportunityMatches(opportunityId: $opportunityId, first: $first) {
921+
edges {
922+
node {
923+
userId
924+
status
925+
previewUser {
926+
id
927+
profileImage
928+
anonId
929+
description
930+
openToWork
931+
seniority
932+
location
933+
topTags
934+
activeSquads {
935+
id
936+
name
937+
handle
938+
}
939+
}
940+
}
941+
}
942+
}
943+
}
944+
`;
945+
946+
const res = await client.query(
947+
GET_OPPORTUNITY_MATCHES_WITH_PREVIEW_USER_QUERY,
948+
{
949+
variables: {
950+
opportunityId: '550e8400-e29b-41d4-a716-446655440001',
951+
first: 10,
952+
},
953+
},
954+
);
955+
956+
expect(res.errors).toBeFalsy();
957+
958+
const acceptedMatch = res.data.opportunityMatches.edges.find(
959+
(e: { node: { status: string } }) =>
960+
e.node.status === 'candidate_accepted',
961+
);
962+
963+
expect(acceptedMatch.node.previewUser).toBeDefined();
964+
expect(acceptedMatch.node.previewUser.id).toBe('2');
965+
expect(acceptedMatch.node.previewUser.anonId).toBeTruthy();
966+
expect(Array.isArray(acceptedMatch.node.previewUser.topTags)).toBe(true);
967+
expect(Array.isArray(acceptedMatch.node.previewUser.activeSquads)).toBe(
968+
true,
969+
);
970+
// Verify activeSquads contains Source objects with expected fields
971+
if (acceptedMatch.node.previewUser.activeSquads.length > 0) {
972+
expect(acceptedMatch.node.previewUser.activeSquads[0]).toHaveProperty(
973+
'id',
974+
);
975+
expect(acceptedMatch.node.previewUser.activeSquads[0]).toHaveProperty(
976+
'name',
977+
);
978+
}
979+
});
980+
912981
it('should include screening, feedback, and application rank', async () => {
913982
loggedUser = '1';
914983

src/graphorm/index.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,6 +1643,13 @@ const obj = new GraphORM({
16431643
parentColumn: 'userId',
16441644
},
16451645
},
1646+
previewUser: {
1647+
relation: {
1648+
isMany: false,
1649+
childColumn: 'id',
1650+
parentColumn: 'userId',
1651+
},
1652+
},
16461653
},
16471654
},
16481655
UserCandidatePreference: {
@@ -1891,18 +1898,23 @@ const obj = new GraphORM({
18911898
},
18921899
},
18931900
activeSquads: {
1894-
select: (_, alias) => `
1895-
ARRAY(
1896-
SELECT sm."sourceId"
1897-
FROM source_member sm
1898-
INNER JOIN source s ON s.id = sm."sourceId"
1899-
WHERE sm."userId" = ${alias}.id
1900-
AND s.type = '${SourceType.Squad}'
1901-
AND s.active = true
1902-
ORDER BY sm."createdAt" DESC
1903-
LIMIT 5
1904-
)
1905-
`,
1901+
relation: {
1902+
isMany: true,
1903+
customRelation: (_, parentAlias, childAlias, qb): QueryBuilder =>
1904+
qb
1905+
.innerJoin(
1906+
SourceMember,
1907+
'sm',
1908+
`sm."sourceId" = "${childAlias}".id`,
1909+
)
1910+
.where(`sm."userId" = ${parentAlias}.id`)
1911+
.andWhere(`"${childAlias}".type = :squadType`, {
1912+
squadType: SourceType.Squad,
1913+
})
1914+
.andWhere(`"${childAlias}".active = true`)
1915+
.orderBy('sm."createdAt"', 'DESC')
1916+
.limit(5),
1917+
},
19061918
},
19071919
},
19081920
},

src/schema/opportunity.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ import { addOpportunityDefaultQuestionFeedback } from '../common/opportunity/que
103103
import { cursorToOffset, offsetToCursor } from 'graphql-relay/index';
104104
import { getShowcaseCompanies } from '../common/opportunity/companies';
105105
import { Opportunity } from '../entity/opportunities/Opportunity';
106+
import type { GQLSource } from './sources';
106107

107108
export interface GQLOpportunity
108109
extends Pick<
@@ -153,7 +154,7 @@ export interface GQLOpportunityPreviewUser extends Pick<User, 'id'> {
153154
lastActivity: Date | null;
154155
topTags: string[] | null;
155156
recentlyRead: GQLTopReaderBadge[] | null;
156-
activeSquads: string[] | null;
157+
activeSquads: GQLSource[] | null;
157158
}
158159

159160
export interface GQLOpportunityPreviewEdge {
@@ -309,6 +310,7 @@ export const typeDefs = /* GraphQL */ `
309310
feedback: [ScreeningAnswer!]!
310311
applicationRank: ApplicationRank!
311312
engagementProfile: EngagementProfile
313+
previewUser: OpportunityPreviewUser
312314
}
313315
314316
type OpportunityMatchEdge {
@@ -441,9 +443,9 @@ export const typeDefs = /* GraphQL */ `
441443
recentlyRead: [UserTopReader!]
442444
443445
"""
444-
Active squad IDs
446+
Active squads
445447
"""
446-
activeSquads: [String!]!
448+
activeSquads: [Source!]!
447449
}
448450
449451
type OpportunityPreviewEdge {
@@ -1281,7 +1283,9 @@ export const resolvers: IResolvers<unknown, BaseContext> = traceResolvers<
12811283
const companies = getShowcaseCompanies();
12821284

12831285
const squads = uniqueifyArray(
1284-
connection.edges.flatMap(({ node }) => node.activeSquads || []),
1286+
connection.edges.flatMap(({ node }) =>
1287+
(node.activeSquads || []).map((squad) => squad.id),
1288+
),
12851289
);
12861290

12871291
return {

0 commit comments

Comments
 (0)