Skip to content

Commit bb2c050

Browse files
authored
Merge pull request #2984 from SeedCompany/refactor/user-repo
User Repo Refactors / KnownLanguage Repo
2 parents ee8c63c + 092df40 commit bb2c050

File tree

6 files changed

+95
-160
lines changed

6 files changed

+95
-160
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Injectable } from '@nestjs/common';
2+
import { node, relation } from 'cypher-query-builder';
3+
import { DateTime } from 'luxon';
4+
import { ID } from '~/common';
5+
import { DtoRepository } from '~/core';
6+
import { ACTIVE } from '~/core/database/query';
7+
import { KnownLanguage, ModifyKnownLanguageArgs } from './dto';
8+
9+
@Injectable()
10+
export class KnownLanguageRepository extends DtoRepository(KnownLanguage) {
11+
async create({
12+
userId,
13+
languageId,
14+
languageProficiency,
15+
}: ModifyKnownLanguageArgs) {
16+
await this.delete({ userId, languageId, languageProficiency });
17+
18+
await this.db
19+
.query()
20+
.matchNode('user', 'User', { id: userId })
21+
.matchNode('language', 'Language', { id: languageId })
22+
.create([
23+
node('user'),
24+
relation('out', '', 'knownLanguage', {
25+
active: true,
26+
createdAt: DateTime.local(),
27+
value: languageProficiency,
28+
}),
29+
node('language'),
30+
])
31+
.run();
32+
}
33+
34+
async delete({
35+
userId,
36+
languageId,
37+
languageProficiency,
38+
}: ModifyKnownLanguageArgs) {
39+
await this.db
40+
.query()
41+
.matchNode('user', 'User', { id: userId })
42+
.matchNode('language', 'Language', { id: languageId })
43+
.match([
44+
[
45+
node('user'),
46+
relation('out', 'rel', 'knownLanguage', {
47+
active: true,
48+
value: languageProficiency,
49+
}),
50+
node('language'),
51+
],
52+
])
53+
.setValues({
54+
'rel.active': false,
55+
})
56+
.run();
57+
}
58+
59+
async list(userId: ID) {
60+
const results = await this.db
61+
.query()
62+
.match([
63+
node('node', 'Language'),
64+
relation('in', 'knownLanguageRel', 'knownLanguage', ACTIVE),
65+
node('user', 'User', { id: userId }),
66+
])
67+
.with('collect(distinct user) as users, node, knownLanguageRel')
68+
.raw(`unwind users as user`)
69+
.return<KnownLanguage>([
70+
'knownLanguageRel.value as proficiency',
71+
'node.id as language',
72+
])
73+
.run();
74+
return results;
75+
}
76+
}

src/components/user/user.edgedb.repository.ts

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
DuplicateException,
44
ID,
55
NotFoundException,
6-
Role,
76
ServerException,
87
Session,
98
} from '~/common';
@@ -99,36 +98,6 @@ export class UserEdgedbRepository extends UserRepository {
9998
}
10099
}
101100

102-
async updateEmail(
103-
user: User,
104-
email: string | null | undefined,
105-
): Promise<void> {
106-
const query = e.update(e.User, () => ({
107-
filter_single: { id: user.id },
108-
set: { email },
109-
}));
110-
try {
111-
await this.edgedb.run(query);
112-
} catch (e) {
113-
if (isExclusivityViolation(e, 'email')) {
114-
throw new DuplicateException(
115-
'person.email',
116-
'Email address is already in use',
117-
e,
118-
);
119-
}
120-
throw e;
121-
}
122-
}
123-
124-
async updateRoles(user: User, roles: Role[]): Promise<void> {
125-
const query = e.update(e.User, () => ({
126-
filter_single: { id: user.id },
127-
set: { roles },
128-
}));
129-
await this.edgedb.run(query);
130-
}
131-
132101
async delete(id: ID, _session: Session, _object: User): Promise<void> {
133102
const query = e.delete(e.User, () => ({
134103
filter_single: { id },

src/components/user/user.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { PartnerModule } from '../partner/partner.module';
99
import { TimeZoneModule } from '../timezone';
1010
import { AssignableRolesResolver } from './assignable-roles.resolver';
1111
import { EducationModule } from './education/education.module';
12+
import { KnownLanguageRepository } from './known-language.repository';
1213
import { KnownLanguageResolver } from './known-language.resolver';
1314
import { UnavailabilityModule } from './unavailability/unavailability.module';
1415
import { UserEdgedbRepository } from './user.edgedb.repository';
@@ -36,6 +37,7 @@ import { UserService } from './user.service';
3637
UserLoader,
3738
UserService,
3839
splitDb(UserRepository, UserEdgedbRepository),
40+
KnownLanguageRepository,
3941
],
4042
exports: [UserService, UserRepository, EducationModule, UnavailabilityModule],
4143
})

src/components/user/user.repository.ts

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ import { Role } from '../authorization';
2929
import {
3030
AssignOrganizationToUser,
3131
CreatePerson,
32-
KnownLanguage,
33-
LanguageProficiency,
3432
RemoveOrganizationFromUser,
3533
UpdateUser,
3634
User,
@@ -123,7 +121,7 @@ export class UserRepository extends DtoRepository<typeof User, [Session | ID]>(
123121
);
124122
}
125123

126-
async updateEmail(
124+
private async updateEmail(
127125
user: User,
128126
email: string | null | undefined,
129127
): Promise<void> {
@@ -153,7 +151,7 @@ export class UserRepository extends DtoRepository<typeof User, [Session | ID]>(
153151
}
154152
}
155153

156-
async updateRoles(user: User, roles: Role[]): Promise<void> {
154+
private async updateRoles(user: User, roles: Role[]): Promise<void> {
157155
const removals = difference(user.roles.value, roles);
158156
const additions = difference(roles, user.roles.value);
159157

@@ -220,68 +218,6 @@ export class UserRepository extends DtoRepository<typeof User, [Session | ID]>(
220218
return result!; // result from paginate() will always have 1 row.
221219
}
222220

223-
async createKnownLanguage(
224-
userId: ID,
225-
languageId: ID,
226-
languageProficiency: LanguageProficiency,
227-
): Promise<void> {
228-
await this.db
229-
.query()
230-
.matchNode('user', 'User', { id: userId })
231-
.matchNode('language', 'Language', { id: languageId })
232-
.create([
233-
node('user'),
234-
relation('out', '', 'knownLanguage', {
235-
active: true,
236-
createdAt: DateTime.local(),
237-
value: languageProficiency,
238-
}),
239-
node('language'),
240-
])
241-
.run();
242-
}
243-
244-
async deleteKnownLanguage(
245-
userId: ID,
246-
languageId: ID,
247-
languageProficiency: LanguageProficiency,
248-
): Promise<void> {
249-
await this.db
250-
.query()
251-
.matchNode('user', 'User', { id: userId })
252-
.matchNode('language', 'Language', { id: languageId })
253-
.match([
254-
[
255-
node('user'),
256-
relation('out', 'rel', 'knownLanguage', {
257-
active: true,
258-
value: languageProficiency,
259-
}),
260-
node('language'),
261-
],
262-
])
263-
.setValues({
264-
'rel.active': false,
265-
})
266-
.run();
267-
}
268-
269-
async listKnownLanguages(userId: ID, _session: Session) {
270-
const results = await this.db
271-
.query()
272-
.match([
273-
node('node', 'Language'),
274-
relation('in', 'knownLanguageRel', 'knownLanguage', ACTIVE),
275-
node('user', 'User', { id: userId }),
276-
])
277-
.with('collect(distinct user) as users, node, knownLanguageRel')
278-
.raw(`unwind users as user`)
279-
.return(['knownLanguageRel.value as proficiency', 'node.id as language'])
280-
.asResult<KnownLanguage>()
281-
.run();
282-
return results;
283-
}
284-
285221
async doesEmailAddressExist(email: string) {
286222
const result = await this.db
287223
.query()

src/components/user/user.resolver.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -295,32 +295,20 @@ export class UserResolver {
295295
})
296296
async createKnownLanguage(
297297
@LoggedInSession() session: Session,
298-
@Args()
299-
{ userId, languageId, languageProficiency }: ModifyKnownLanguageArgs,
298+
@Args() args: ModifyKnownLanguageArgs,
300299
): Promise<User> {
301-
await this.userService.createKnownLanguage(
302-
userId,
303-
languageId,
304-
languageProficiency,
305-
session,
306-
);
307-
return await this.userService.readOne(userId, session);
300+
await this.userService.createKnownLanguage(args);
301+
return await this.userService.readOne(args.userId, session);
308302
}
309303

310304
@Mutation(() => User, {
311305
description: 'Delete known language from user',
312306
})
313307
async deleteKnownLanguage(
314308
@LoggedInSession() session: Session,
315-
@Args()
316-
{ userId, languageId, languageProficiency }: ModifyKnownLanguageArgs,
309+
@Args() args: ModifyKnownLanguageArgs,
317310
): Promise<User> {
318-
await this.userService.deleteKnownLanguage(
319-
userId,
320-
languageId,
321-
languageProficiency,
322-
session,
323-
);
324-
return await this.userService.readOne(userId, session);
311+
await this.userService.deleteKnownLanguage(args);
312+
return await this.userService.readOne(args.userId, session);
325313
}
326314
}

src/components/user/user.service.ts

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { property } from '../../core/database/query';
1414
import { mapListResults } from '../../core/database/results';
1515
import { Privileges, Role } from '../authorization';
1616
import { AssignableRoles } from '../authorization/dto/assignable-roles';
17-
import { LanguageService } from '../language';
1817
import {
1918
LocationListInput,
2019
LocationService,
@@ -33,19 +32,19 @@ import {
3332
import {
3433
AssignOrganizationToUser,
3534
CreatePerson,
36-
KnownLanguage,
35+
ModifyKnownLanguageArgs,
3736
RemoveOrganizationFromUser,
3837
UpdateUser,
3938
User,
4039
UserListInput,
4140
UserListOutput,
4241
} from './dto';
43-
import { LanguageProficiency } from './dto/language-proficiency.enum';
4442
import {
4543
EducationListInput,
4644
EducationService,
4745
SecuredEducationList,
4846
} from './education';
47+
import { KnownLanguageRepository } from './known-language.repository';
4948
import {
5049
SecuredUnavailabilityList,
5150
UnavailabilityListInput,
@@ -63,7 +62,7 @@ export class UserService {
6362
private readonly unavailabilities: UnavailabilityService,
6463
private readonly privileges: Privileges,
6564
private readonly locationService: LocationService,
66-
private readonly languageService: LanguageService,
65+
private readonly knownLanguages: KnownLanguageRepository,
6766
private readonly userRepo: UserRepository,
6867
@Logger('user:service') private readonly logger: ILogger,
6968
) {}
@@ -303,56 +302,21 @@ export class UserService {
303302
);
304303
}
305304

306-
async createKnownLanguage(
307-
userId: ID,
308-
languageId: ID,
309-
languageProficiency: LanguageProficiency,
310-
_session: Session,
311-
): Promise<void> {
312-
try {
313-
await this.deleteKnownLanguage(
314-
userId,
315-
languageId,
316-
languageProficiency,
317-
_session,
318-
);
319-
await this.userRepo.createKnownLanguage(
320-
userId,
321-
languageId,
322-
languageProficiency,
323-
);
324-
} catch (e) {
325-
throw new ServerException('Could not create known language', e);
326-
}
305+
async createKnownLanguage(args: ModifyKnownLanguageArgs) {
306+
await this.knownLanguages.create(args);
327307
}
328308

329-
async deleteKnownLanguage(
330-
userId: ID,
331-
languageId: ID,
332-
languageProficiency: LanguageProficiency,
333-
_session: Session,
334-
): Promise<void> {
335-
try {
336-
await this.userRepo.deleteKnownLanguage(
337-
userId,
338-
languageId,
339-
languageProficiency,
340-
);
341-
} catch (e) {
342-
throw new ServerException('Could not delete known language', e);
343-
}
309+
async deleteKnownLanguage(args: ModifyKnownLanguageArgs) {
310+
await this.knownLanguages.delete(args);
344311
}
345312

346-
async listKnownLanguages(
347-
userId: ID,
348-
session: Session,
349-
): Promise<readonly KnownLanguage[]> {
313+
async listKnownLanguages(userId: ID, session: Session) {
350314
const user = await this.userRepo.readOne(userId, session);
351315
const perms = this.privileges.for(session, User, user).all.knownLanguage;
352316
if (!perms.read) {
353317
return [];
354318
}
355-
return await this.userRepo.listKnownLanguages(userId, session);
319+
return await this.knownLanguages.list(userId);
356320
}
357321

358322
async checkEmail(email: string): Promise<boolean> {

0 commit comments

Comments
 (0)