Skip to content

Commit d83b135

Browse files
committed
Refactor getting flattened GQL input
This will make it easier for other input exceptions to use this info
1 parent d712d2f commit d83b135

File tree

3 files changed

+48
-36
lines changed

3 files changed

+48
-36
lines changed
Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
import { ArgumentsHost } from '@nestjs/common';
2-
import {
3-
GqlContextType as ContextKey,
4-
GqlExecutionContext,
5-
} from '@nestjs/graphql';
62
import { lowerCase, upperFirst } from 'lodash';
73
import type { ExclusivityViolationError } from '~/core/edgedb';
84
import { InputException } from './input.exception';
@@ -27,38 +23,14 @@ export class DuplicateException extends InputException {
2723

2824
// Attempt to add path prefix automatically to the property name, based
2925
// on given GQL input.
30-
if (context && context.getType<ContextKey>() === 'graphql') {
31-
let gqlArgs = GqlExecutionContext.create(context as any).getArgs();
32-
33-
// unwind single `input` argument, based on our own conventions
34-
if (Object.keys(gqlArgs).length === 1 && 'input' in gqlArgs) {
35-
gqlArgs = gqlArgs.input;
36-
}
37-
38-
const flattened = flattenObject(gqlArgs);
39-
// Guess the correct path based on property name.
40-
// This kinda assumes the property name will be unique amongst all the input.
41-
const guessedPath = Object.keys(flattened).find(
42-
(path) => property === path || path.endsWith('.' + property),
43-
);
44-
property = guessedPath ?? property;
45-
}
26+
// This kinda assumes the property name will be unique amongst all the input.
27+
const guessedPath = Object.keys(
28+
InputException.getFlattenInput(context),
29+
).find((path) => property === path || path.endsWith('.' + property));
30+
property = guessedPath ?? property;
4631

4732
const ex = new DuplicateException(property, message, exception);
4833
ex.stack = exception.stack;
4934
return ex;
5035
}
5136
}
52-
53-
const flattenObject = (obj: object, prefix = '') => {
54-
const result: Record<string, any> = {};
55-
for (const [key, value] of Object.entries(obj)) {
56-
if (value && typeof value === 'object' && !Array.isArray(value)) {
57-
const nestedObj = flattenObject(value, prefix + key + '.');
58-
Object.assign(result, nestedObj);
59-
} else {
60-
result[prefix + key] = value;
61-
}
62-
}
63-
return result;
64-
};

src/common/exceptions/input.exception.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import { ArgumentsHost } from '@nestjs/common';
2+
import {
3+
GqlContextType as ContextKey,
4+
GqlExecutionContext,
5+
} from '@nestjs/graphql';
16
import { ClientException } from './exception';
27

38
export type InputExceptionArgs =
@@ -104,4 +109,35 @@ export class InputException extends ClientException {
104109
}
105110
return [message, field, previous] as const;
106111
}
112+
113+
static getFlattenInput(context?: ArgumentsHost) {
114+
if (!context || context.getType<ContextKey>() !== 'graphql') {
115+
return {};
116+
}
117+
const gqlContext =
118+
context instanceof GqlExecutionContext
119+
? context
120+
: GqlExecutionContext.create(context as any);
121+
let gqlArgs = gqlContext.getArgs();
122+
123+
// unwind single `input` argument, based on our own conventions
124+
if (Object.keys(gqlArgs).length === 1 && 'input' in gqlArgs) {
125+
gqlArgs = gqlArgs.input;
126+
}
127+
128+
return flattenObject(gqlArgs);
129+
}
107130
}
131+
132+
const flattenObject = (obj: object, prefix = '') => {
133+
const result: Record<string, any> = {};
134+
for (const [key, value] of Object.entries(obj)) {
135+
if (value && typeof value === 'object' && !Array.isArray(value)) {
136+
const nestedObj = flattenObject(value, prefix + key + '.');
137+
Object.assign(result, nestedObj);
138+
} else {
139+
result[prefix + key] = value;
140+
}
141+
}
142+
return result;
143+
};

src/core/exception/exception.normalizer.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,17 @@ export class ExceptionNormalizer {
114114
};
115115
}
116116

117+
const gqlContext =
118+
context && context.getType<ContextKey>() === 'graphql'
119+
? GqlExecutionContext.create(context as any)
120+
: undefined;
121+
117122
if (ex instanceof ExclusivityViolationError) {
118-
ex = DuplicateException.fromDB(ex, context);
123+
ex = DuplicateException.fromDB(ex, gqlContext);
119124
} else if (ex instanceof Edge.EdgeDBError) {
120125
// Mask actual DB error with a nicer user error message.
121126
let message = 'Failed';
122-
if (context && context.getType<ContextKey>() === 'graphql') {
123-
const gqlContext = GqlExecutionContext.create(context as any);
127+
if (gqlContext) {
124128
const info = gqlContext.getInfo<GraphQLResolveInfo>();
125129
if (info.operation.operation === 'mutation') {
126130
message += ` to ${lowerCase(info.fieldName)}`;

0 commit comments

Comments
 (0)