Skip to content

Commit 46f9805

Browse files
authored
Merge pull request #3275 from SeedCompany/intern-name-filter
2 parents fe70d06 + e07e98c commit 46f9805

File tree

4 files changed

+85
-6
lines changed

4 files changed

+85
-6
lines changed

src/components/engagement/dto/list-engagements.dto.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '~/common';
99
import { LanguageFilters } from '../../language/dto';
1010
import { ProjectFilters } from '../../project/dto';
11+
import { UserFilters } from '../../user/dto';
1112
import {
1213
Engagement,
1314
IEngagement,
@@ -26,6 +27,8 @@ export abstract class EngagementFilters {
2627

2728
@Field({
2829
nullable: true,
30+
description:
31+
'Only engagements whose project or engaged entity (language / user) name match',
2932
})
3033
readonly name?: string;
3134

@@ -38,10 +41,20 @@ export abstract class EngagementFilters {
3841
@FilterField(() => ProjectFilters)
3942
readonly project?: ProjectFilters & {};
4043

44+
@Field({
45+
nullable: true,
46+
description:
47+
'Only engagements whose engaged entity (language / user) name match',
48+
})
49+
readonly engagedName?: string;
50+
4151
readonly languageId?: ID;
4252
@FilterField(() => LanguageFilters)
4353
readonly language?: LanguageFilters & {};
4454

55+
@FilterField(() => UserFilters)
56+
readonly intern?: UserFilters & {};
57+
4558
readonly partnerId?: ID<'Partner'>;
4659
}
4760

src/components/engagement/engagement.repository.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
import { ProjectType } from '../project/dto';
5959
import { projectFilters } from '../project/project-filters.query';
6060
import { projectSorters } from '../project/project.repository';
61+
import { userFilters } from '../user';
6162
import {
6263
CreateInternshipEngagement,
6364
CreateLanguageEngagement,
@@ -518,6 +519,7 @@ export class EngagementRepository extends CommonRepository {
518519
@OnIndex('schema')
519520
private async createSchemaIndexes() {
520521
await this.db.query().apply(NameIndex.create()).run();
522+
await this.db.query().apply(EngagedNameIndex.create()).run();
521523
await this.db.query().apply(LanguageNameIndex.create()).run();
522524
await this.db.query().apply(InternshipNameIndex.create()).run();
523525
}
@@ -552,6 +554,22 @@ export const engagementFilters = filter.define(() => EngagementFilters, {
552554
separateQueryForEachWord: true,
553555
minScore: 0.9,
554556
}),
557+
engagedName: filter.fullText({
558+
index: () => EngagedNameIndex,
559+
matchToNode: (q) =>
560+
q.match([
561+
node('node', 'Engagement'),
562+
relation('out', '', undefined, ACTIVE),
563+
node('', 'BaseNode'),
564+
relation('out', '', undefined, ACTIVE),
565+
node('match'),
566+
]),
567+
// Treat each word as a separate search term
568+
// Each word could point to a different node
569+
// i.e. "first - last"
570+
separateQueryForEachWord: true,
571+
minScore: 0.9,
572+
}),
555573
projectId: filter.pathExists((id) => [
556574
node('node'),
557575
relation('in', '', 'engagement'),
@@ -592,6 +610,15 @@ export const engagementFilters = filter.define(() => EngagementFilters, {
592610
node('node', 'Language'),
593611
]),
594612
),
613+
intern: filter.sub(() => userFilters)((sub) =>
614+
sub
615+
.with('node as eng')
616+
.match([
617+
node('eng'),
618+
relation('out', '', 'intern'),
619+
node('node', 'User'),
620+
]),
621+
),
595622
});
596623

597624
export const engagementSorters = defineSorters(IEngagement, {
@@ -714,6 +741,12 @@ const NameIndex = FullTextIndex({
714741
properties: 'value',
715742
analyzer: 'standard-folding',
716743
});
744+
const EngagedNameIndex = FullTextIndex({
745+
indexName: 'EngagedName',
746+
labels: ['LanguageName', 'LanguageDisplayName', 'UserName'],
747+
properties: 'value',
748+
analyzer: 'standard-folding',
749+
});
717750
const LanguageNameIndex = FullTextIndex({
718751
indexName: 'LanguageEngagementName',
719752
labels: ['ProjectName', 'LanguageName', 'LanguageDisplayName'],

src/components/user/dto/list-users.dto.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import { User } from './user.dto';
44

55
@InputType()
66
export abstract class UserFilters {
7+
@Field({
8+
nullable: true,
9+
})
10+
readonly name?: string;
11+
712
@Field({
813
description: 'Only users that are pinned/unpinned by the requesting user',
914
nullable: true,

src/components/user/user.repository.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import {
1010
Session,
1111
UnsecuredDto,
1212
} from '~/common';
13-
import { DtoRepository, UniquenessError } from '~/core/database';
13+
import { DtoRepository, OnIndex, UniquenessError } from '~/core/database';
1414
import {
1515
ACTIVE,
1616
createNode,
1717
createProperty,
1818
deactivateProperty,
1919
defineSorters,
2020
filter,
21+
FullTextIndex,
2122
matchProps,
2223
merge,
2324
paginate,
@@ -32,6 +33,7 @@ import {
3233
SystemAgent,
3334
UpdateUser,
3435
User,
36+
UserFilters,
3537
UserListInput,
3638
} from './dto';
3739

@@ -224,11 +226,7 @@ export class UserRepository extends DtoRepository<typeof User, [Session | ID]>(
224226
.query()
225227
.matchNode('node', 'User')
226228
.match(requestingUser(session))
227-
.apply(
228-
filter.builder(input.filter ?? {}, {
229-
pinned: filter.isPinned,
230-
}),
231-
)
229+
.apply(userFilters(input.filter))
232230
.apply(this.privileges.forUser(session).filterToReadable())
233231
.apply(sortWith(userSorters, input))
234232
.apply(paginate(input, this.hydrate(session.userId)))
@@ -364,6 +362,36 @@ export class UserRepository extends DtoRepository<typeof User, [Session | ID]>(
364362
hydrateAsNeo4j(session: Session | ID) {
365363
return this.hydrate(session);
366364
}
365+
366+
@OnIndex('schema')
367+
private async createSchemaIndexes() {
368+
await this.db.query().apply(NameIndex.create()).run();
369+
}
367370
}
368371

372+
export const userFilters = filter.define(() => UserFilters, {
373+
pinned: filter.isPinned,
374+
name: filter.fullText({
375+
index: () => NameIndex,
376+
matchToNode: (q) =>
377+
q.match([
378+
node('node', 'User'),
379+
relation('out', '', undefined, ACTIVE),
380+
node('match'),
381+
]),
382+
// Treat each word as a separate search term
383+
// Each word could point to a different node
384+
// i.e. "first last"
385+
separateQueryForEachWord: true,
386+
minScore: 0.9,
387+
}),
388+
});
389+
369390
export const userSorters = defineSorters(User, {});
391+
392+
const NameIndex = FullTextIndex({
393+
indexName: 'UserName',
394+
labels: 'UserName',
395+
properties: 'value',
396+
analyzer: 'standard-folding',
397+
});

0 commit comments

Comments
 (0)