Skip to content

Commit e626ee1

Browse files
authored
Merge pull request #3392 from SeedCompany/dry-create-failed
2 parents 1c88098 + c2b679a commit e626ee1

38 files changed

+264
-93
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { EnhancedResource } from '~/common';
2+
import type { ResourceLike } from '~/core';
3+
import { ServerException } from './exception';
4+
5+
export class CreationFailed extends ServerException {
6+
readonly resource: EnhancedResource<any>;
7+
constructor(
8+
resource: ResourceLike,
9+
options?: { message?: string; cause?: Error },
10+
) {
11+
const res = EnhancedResource.resolve(resource);
12+
super(options?.message ?? `Failed to create ${res.name}`, options?.cause);
13+
this.resource = res;
14+
}
15+
}
16+
17+
export class ReadAfterCreationFailed extends CreationFailed {
18+
constructor(
19+
resource: ResourceLike,
20+
options?: { message?: string; cause?: Error },
21+
) {
22+
const res = EnhancedResource.resolve(resource);
23+
super(res, {
24+
message: `Failed to retrieve ${res.name} after creation`,
25+
...options,
26+
});
27+
}
28+
}

src/common/exceptions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './unauthenticated.exception';
77
export * from './unauthorized.exception';
88
export * from './service-unavailable.exception';
99
export * from './invalid-id-for-type.exception';
10+
export * from './creation-failed.exception';

src/common/resource.dto.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
FnLike,
55
mapValues,
66
setInspectOnClass,
7+
setToJson,
78
} from '@seedcompany/common';
89
import { LazyGetter as Once } from 'lazy-get-decorator';
910
import { DateTime } from 'luxon';
@@ -106,6 +107,9 @@ export class EnhancedResource<T extends ResourceShape<any>> {
106107
>();
107108

108109
static resolve(ref: ResourceLike) {
110+
if (ref && typeof ref !== 'string') {
111+
return EnhancedResource.of(ref);
112+
}
109113
if (!EnhancedResource.resourcesHost) {
110114
throw new ServerException('Cannot resolve without ResourcesHost');
111115
}
@@ -295,6 +299,7 @@ export class EnhancedResource<T extends ResourceShape<any>> {
295299
setInspectOnClass(EnhancedResource, (res) => ({ collapsed }) => {
296300
return collapsed(res.name, 'Enhanced');
297301
});
302+
setToJson(EnhancedResource, (res) => ({ name: res.name }));
298303

299304
export interface EnhancedRelation<TResourceStatic extends ResourceShape<any>> {
300305
readonly name: RelKey<TResourceStatic>;

src/components/budget/budget-record.repository.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common';
22
import { node, Query, relation } from 'cypher-query-builder';
33
import { pickBy } from 'lodash';
44
import {
5+
CreationFailed,
56
ID,
67
labelForView,
78
NotFoundException,
89
ObjectView,
9-
ServerException,
1010
Session,
1111
UnsecuredDto,
1212
} from '~/common';
@@ -69,7 +69,7 @@ export class BudgetRecordRepository extends DtoRepository<
6969
.return<{ id: ID }>('node.id as id')
7070
.first();
7171
if (!result) {
72-
throw new ServerException('Failed to create a budget record');
72+
throw new CreationFailed(BudgetRecord);
7373
}
7474
return result.id;
7575
}

src/components/budget/budget.repository.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common';
22
import { inArray, node, Query, relation } from 'cypher-query-builder';
33
import { pickBy } from 'lodash';
44
import {
5+
CreationFailed,
56
ID,
67
labelForView,
78
NotFoundException,
89
ObjectView,
9-
ServerException,
1010
Session,
1111
UnsecuredDto,
1212
viewOfChangeset,
@@ -64,7 +64,7 @@ export class BudgetRepository extends DtoRepository<
6464
.first();
6565

6666
if (!result) {
67-
throw new ServerException('Failed to create budget');
67+
throw new CreationFailed(Budget);
6868
}
6969

7070
return result.id;

src/components/budget/budget.service.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Injectable } from '@nestjs/common';
22
import {
3+
CreationFailed,
34
DuplicateException,
45
generateId,
56
ID,
@@ -78,7 +79,7 @@ export class BudgetService {
7879
userId: session.userId,
7980
exception,
8081
});
81-
throw new ServerException('Could not create budget', exception);
82+
throw new CreationFailed(Budget, { cause: exception });
8283
}
8384
}
8485

@@ -119,7 +120,7 @@ export class BudgetService {
119120
userId: session.userId,
120121
exception,
121122
});
122-
throw new ServerException('Could not create Budget Record', exception);
123+
throw new CreationFailed(BudgetRecord, { cause: exception });
123124
}
124125
}
125126

src/components/ceremony/ceremony.repository.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Injectable } from '@nestjs/common';
22
import { node, Query, relation } from 'cypher-query-builder';
3-
import { ID, ServerException, Session, UnsecuredDto } from '~/common';
3+
import { CreationFailed, ID, Session, UnsecuredDto } from '~/common';
44
import { DtoRepository } from '~/core/database';
55
import {
66
ACTIVE,
@@ -38,7 +38,7 @@ export class CeremonyRepository extends DtoRepository<
3838
.first();
3939

4040
if (!result) {
41-
throw new ServerException('failed to create a ceremony');
41+
throw new CreationFailed(Ceremony);
4242
}
4343
return result;
4444
}

src/components/comments/comment.service.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Injectable } from '@nestjs/common';
22
import { difference } from 'lodash';
33
import {
4+
CreationFailed,
45
ID,
56
InvalidIdForTypeException,
67
isIdLike,
@@ -52,7 +53,7 @@ export class CommentService {
5253
try {
5354
const result = await this.repo.create(input, session);
5455
if (!result) {
55-
throw new ServerException('Failed to create comment');
56+
throw new CreationFailed(Comment);
5657
}
5758
dto = await this.repo.readOne(result.id);
5859
} catch (exception) {
@@ -66,7 +67,7 @@ export class CommentService {
6667
);
6768
}
6869

69-
throw new ServerException('Failed to create comment', exception);
70+
throw new CreationFailed(Comment, { cause: exception });
7071
}
7172

7273
const mentionees = this.mentionNotificationService.extract(dto);

src/components/engagement/engagement.repository.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ import { difference, pickBy, upperFirst } from 'lodash';
1212
import { DateTime } from 'luxon';
1313
import { MergeExclusive } from 'type-fest';
1414
import {
15+
CreationFailed,
1516
DuplicateException,
1617
generateId,
1718
ID,
1819
InputException,
1920
labelForView,
2021
NotFoundException,
2122
ObjectView,
23+
ReadAfterCreationFailed,
2224
ServerException,
2325
Session,
2426
typenameForView,
@@ -268,7 +270,7 @@ export class EngagementRepository extends CommonRepository {
268270

269271
const result = await query.first();
270272
if (!result) {
271-
throw new ServerException('Could not create Language Engagement');
273+
throw new CreationFailed(LanguageEngagement);
272274
}
273275

274276
await this.files.createDefinedFile(
@@ -285,7 +287,11 @@ export class EngagementRepository extends CommonRepository {
285287
result.id,
286288
session,
287289
viewOfChangeset(changeset),
288-
)) as UnsecuredDto<LanguageEngagement>;
290+
).catch((e) => {
291+
throw e instanceof NotFoundException
292+
? new ReadAfterCreationFailed(LanguageEngagement)
293+
: e;
294+
})) as UnsecuredDto<LanguageEngagement>;
289295
}
290296

291297
async createInternshipEngagement(
@@ -359,7 +365,7 @@ export class EngagementRepository extends CommonRepository {
359365
);
360366
}
361367

362-
throw new ServerException('Could not create Internship Engagement');
368+
throw new CreationFailed(InternshipEngagement);
363369
}
364370

365371
await this.files.createDefinedFile(
@@ -376,7 +382,11 @@ export class EngagementRepository extends CommonRepository {
376382
result.id,
377383
session,
378384
viewOfChangeset(changeset),
379-
)) as UnsecuredDto<InternshipEngagement>;
385+
).catch((e) => {
386+
throw e instanceof NotFoundException
387+
? new ReadAfterCreationFailed(InternshipEngagement)
388+
: e;
389+
})) as UnsecuredDto<InternshipEngagement>;
380390
}
381391

382392
getActualLanguageChanges = getChanges(LanguageEngagement);

src/components/ethno-art/ethno-art.repository.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Injectable } from '@nestjs/common';
22
import { Query } from 'cypher-query-builder';
33
import {
4+
CreationFailed,
45
DuplicateException,
56
ID,
7+
NotFoundException,
68
PaginatedListType,
7-
ServerException,
9+
ReadAfterCreationFailed,
810
Session,
911
UnsecuredDto,
1012
} from '~/common';
@@ -55,7 +57,7 @@ export class EthnoArtRepository extends DtoRepository(EthnoArt) {
5557
.first();
5658

5759
if (!result) {
58-
throw new ServerException('Failed to create ethno art');
60+
throw new CreationFailed(EthnoArt);
5961
}
6062

6163
await this.scriptureRefsService.create(
@@ -64,7 +66,11 @@ export class EthnoArtRepository extends DtoRepository(EthnoArt) {
6466
session,
6567
);
6668

67-
return await this.readOne(result.id);
69+
return await this.readOne(result.id).catch((e) => {
70+
throw e instanceof NotFoundException
71+
? new ReadAfterCreationFailed(EthnoArt)
72+
: e;
73+
});
6874
}
6975

7076
async update(input: UpdateEthnoArt) {

0 commit comments

Comments
 (0)