Skip to content

Commit a7e9862

Browse files
atGit2021CarsonF
andauthored
Add Project.partnership(partner: id) (#3271)
Co-authored-by: Carson Full <[email protected]>
1 parent ab4bda3 commit a7e9862

File tree

7 files changed

+113
-1
lines changed

7 files changed

+113
-1
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './partnership.service';
22
export * from './partnership.loader';
3+
export * from './partnership-by-project-and-partner.loader';
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { ID } from '~/common';
2+
import {
3+
LoaderFactory,
4+
LoaderOptionsOf,
5+
SessionAwareLoaderStrategy,
6+
} from '~/core';
7+
import { Partnership } from './dto';
8+
import { PartnershipService } from './partnership.service';
9+
10+
export interface PartnershipByProjectAndPartnerInput {
11+
project: ID<'Project'>;
12+
partner: ID<'Partner'>;
13+
}
14+
15+
@LoaderFactory()
16+
export class PartnershipByProjectAndPartnerLoader extends SessionAwareLoaderStrategy<
17+
{ id: PartnershipByProjectAndPartnerInput; partnership: Partnership },
18+
PartnershipByProjectAndPartnerInput,
19+
string
20+
> {
21+
constructor(private readonly service: PartnershipService) {
22+
super();
23+
}
24+
25+
getOptions() {
26+
return {
27+
cacheKeyFn: (input) => `${input.project}:${input.partner}`,
28+
} satisfies LoaderOptionsOf<PartnershipByProjectAndPartnerLoader>;
29+
}
30+
31+
async loadMany(input: readonly PartnershipByProjectAndPartnerInput[]) {
32+
return await this.service.readManyByProjectAndPartner(input, this.session);
33+
}
34+
}

src/components/partnership/partnership.edgedb.repository.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
22
import { ID, PublicOf } from '~/common';
33
import { e, RepoFor } from '~/core/edgedb';
44
import { Partnership } from './dto';
5+
import type { PartnershipByProjectAndPartnerInput } from './partnership-by-project-and-partner.loader';
56
import { PartnershipRepository } from './partnership.repository';
67

78
@Injectable()
@@ -28,6 +29,26 @@ export class PartnershipEdgeDBRepository
2829
})
2930
implements PublicOf<PartnershipRepository>
3031
{
32+
async readManyByProjectAndPartner(
33+
input: readonly PartnershipByProjectAndPartnerInput[],
34+
) {
35+
return await this.db.run(this.readManyByProjectAndPartnerQuery, { input });
36+
}
37+
private readonly readManyByProjectAndPartnerQuery = e.params(
38+
{ input: e.array(e.tuple({ project: e.uuid, partner: e.uuid })) },
39+
({ input }) =>
40+
e.for(e.array_unpack(input), ({ project, partner }) =>
41+
e.select(e.Partnership, (partnership) => ({
42+
...this.hydrate(partnership),
43+
filter: e.op(
44+
e.op(partnership.project, '=', e.cast(e.Project, project)),
45+
'and',
46+
e.op(partnership.partner, '=', e.cast(e.Partner, partner)),
47+
),
48+
})),
49+
),
50+
);
51+
3152
async isFirstPartnership(projectId: ID) {
3253
const project = e.cast(e.Project, e.uuid(projectId));
3354
const query = e.op('not', e.op('exists', project.partnerships));

src/components/partnership/partnership.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { FileModule } from '../file/file.module';
66
import { PartnerModule } from '../partner/partner.module';
77
import { ProjectModule } from '../project/project.module';
88
import * as handlers from './handlers';
9+
import { PartnershipByProjectAndPartnerLoader } from './partnership-by-project-and-partner.loader';
910
import { PartnershipEdgeDBRepository } from './partnership.edgedb.repository';
1011
import { PartnershipLoader } from './partnership.loader';
1112
import { PartnershipRepository } from './partnership.repository';
@@ -25,6 +26,7 @@ import { PartnershipService } from './partnership.service';
2526
PartnershipService,
2627
splitDb(PartnershipRepository, PartnershipEdgeDBRepository),
2728
PartnershipLoader,
29+
PartnershipByProjectAndPartnerLoader,
2830
...Object.values(handlers),
2931
],
3032
exports: [PartnershipService],

src/components/partnership/partnership.repository.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
paginate,
3232
requestingUser,
3333
sortWith,
34+
variable,
3435
whereNotDeletedInChangeset,
3536
} from '~/core/database/query';
3637
import { FileService } from '../file';
@@ -44,6 +45,7 @@ import {
4445
PartnershipListInput,
4546
UpdatePartnership,
4647
} from './dto';
48+
import type { PartnershipByProjectAndPartnerInput } from './partnership-by-project-and-partner.loader';
4749

4850
@Injectable()
4951
export class PartnershipRepository extends DtoRepository<
@@ -162,6 +164,25 @@ export class PartnershipRepository extends DtoRepository<
162164
.run();
163165
}
164166

167+
async readManyByProjectAndPartner(
168+
input: readonly PartnershipByProjectAndPartnerInput[],
169+
session: Session,
170+
) {
171+
return await this.db
172+
.query()
173+
.unwind([...input], 'input')
174+
.match([
175+
node('project', 'Project', { id: variable('input.project.id') }),
176+
relation('out', '', 'partnership', ACTIVE),
177+
node('node'),
178+
relation('out', '', 'partner', ACTIVE),
179+
node('partner', 'Partner', { id: variable('input.partner.id') }),
180+
])
181+
.apply(this.hydrate(session))
182+
.map('dto')
183+
.run();
184+
}
185+
165186
protected override hydrate(session: Session, view?: ObjectView) {
166187
return (query: Query) =>
167188
query

src/components/partnership/partnership.service.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
PartnershipUpdatedEvent,
3434
PartnershipWillDeleteEvent,
3535
} from './events';
36+
import type { PartnershipByProjectAndPartnerInput } from './partnership-by-project-and-partner.loader';
3637
import { PartnershipRepository } from './partnership.repository';
3738

3839
@Injectable()
@@ -122,6 +123,20 @@ export class PartnershipService {
122123
return partnerships.map((dto) => this.secure(dto, session));
123124
}
124125

126+
async readManyByProjectAndPartner(
127+
input: readonly PartnershipByProjectAndPartnerInput[],
128+
session: Session,
129+
) {
130+
const partnerships = await this.repo.readManyByProjectAndPartner(
131+
input,
132+
session,
133+
);
134+
return partnerships.map((dto) => ({
135+
id: { project: dto.project.id, partner: dto.partner.id },
136+
partnership: this.secure(dto, session),
137+
}));
138+
}
139+
125140
secure(dto: UnsecuredDto<Partnership>, session: Session) {
126141
return this.privileges.for(session, Partnership).secure(dto);
127142
}

src/components/project/project.resolver.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@ import {
4040
} from '../location/dto';
4141
import { OrganizationLoader } from '../organization';
4242
import { SecuredOrganization } from '../organization/dto';
43-
import { PartnershipLoader } from '../partnership';
4443
import {
44+
PartnershipByProjectAndPartnerLoader,
45+
PartnershipLoader,
46+
} from '../partnership';
47+
import {
48+
Partnership,
4549
PartnershipListInput,
4650
SecuredPartnership,
4751
SecuredPartnershipList,
@@ -254,6 +258,20 @@ export class ProjectResolver {
254258
return list;
255259
}
256260

261+
@ResolveField(() => Partnership)
262+
async partnership(
263+
@Parent() project: Project,
264+
@IdArg({ name: 'partner' }) partnerId: ID,
265+
@Loader(PartnershipByProjectAndPartnerLoader)
266+
loader: LoaderOf<PartnershipByProjectAndPartnerLoader>,
267+
): Promise<Partnership> {
268+
const result = await loader.load({
269+
project: project.id,
270+
partner: partnerId,
271+
});
272+
return result.partnership;
273+
}
274+
257275
@ResolveField(() => SecuredDirectory, {
258276
description: 'The root filesystem directory of this project',
259277
})

0 commit comments

Comments
 (0)