-
-
Notifications
You must be signed in to change notification settings - Fork 798
/
externalObjects.ts
93 lines (80 loc) · 3.22 KB
/
externalObjects.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { GraphQLSchema, GraphQLError, GraphQLObjectType, SelectionSetNode } from 'graphql';
import { mergeDeep, relocatedError, GraphQLExecutionContext, collectFields } from '@graphql-tools/utils';
import { SubschemaConfig, ExternalObject } from './types';
import { OBJECT_SUBSCHEMA_SYMBOL, FIELD_SUBSCHEMA_MAP_SYMBOL, UNPATHED_ERRORS_SYMBOL } from './symbols';
export function isExternalObject(data: any): data is ExternalObject {
return data[UNPATHED_ERRORS_SYMBOL] !== undefined;
}
export function annotateExternalObject(
object: any,
errors: Array<GraphQLError>,
subschema: GraphQLSchema | SubschemaConfig
): ExternalObject {
Object.defineProperties(object, {
[OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema },
[FIELD_SUBSCHEMA_MAP_SYMBOL]: { value: Object.create(null) },
[UNPATHED_ERRORS_SYMBOL]: { value: errors },
});
return object;
}
export function getSubschema(object: ExternalObject, responseKey: string): GraphQLSchema | SubschemaConfig {
return object[FIELD_SUBSCHEMA_MAP_SYMBOL][responseKey] ?? object[OBJECT_SUBSCHEMA_SYMBOL];
}
export function getUnpathedErrors(object: ExternalObject): Array<GraphQLError> {
return object[UNPATHED_ERRORS_SYMBOL];
}
export function mergeExternalObjects(
schema: GraphQLSchema,
path: Array<string | number>,
typeName: string,
target: ExternalObject,
sources: Array<ExternalObject>,
selectionSets: Array<SelectionSetNode>
): ExternalObject {
const results: Array<any> = [];
let errors: Array<GraphQLError> = [];
sources.forEach((source, index) => {
if (source instanceof GraphQLError || source === null) {
const selectionSet = selectionSets[index];
const fieldNodes = collectFields(
{
schema,
variableValues: {},
fragments: {},
} as GraphQLExecutionContext,
schema.getType(typeName) as GraphQLObjectType,
selectionSet,
Object.create(null),
Object.create(null)
);
const nullResult = {};
Object.keys(fieldNodes).forEach(responseKey => {
nullResult[responseKey] =
source instanceof GraphQLError ? relocatedError(source, path.concat([responseKey])) : null;
});
results.push(nullResult);
} else {
errors = errors.concat(source[UNPATHED_ERRORS_SYMBOL]);
results.push(source);
}
});
const combinedResult: ExternalObject = results.reduce(mergeDeep, target);
const newFieldSubschemaMap = target[FIELD_SUBSCHEMA_MAP_SYMBOL] ?? Object.create(null);
results.forEach((source: ExternalObject) => {
const objectSubschema = source[OBJECT_SUBSCHEMA_SYMBOL];
const fieldSubschemaMap = source[FIELD_SUBSCHEMA_MAP_SYMBOL];
if (fieldSubschemaMap === undefined) {
Object.keys(source).forEach(responseKey => {
newFieldSubschemaMap[responseKey] = objectSubschema;
});
} else {
Object.keys(source).forEach(responseKey => {
newFieldSubschemaMap[responseKey] = fieldSubschemaMap[responseKey] ?? objectSubschema;
});
}
});
combinedResult[FIELD_SUBSCHEMA_MAP_SYMBOL] = newFieldSubschemaMap;
combinedResult[OBJECT_SUBSCHEMA_SYMBOL] = target[OBJECT_SUBSCHEMA_SYMBOL];
combinedResult[UNPATHED_ERRORS_SYMBOL] = target[UNPATHED_ERRORS_SYMBOL].concat(errors);
return combinedResult;
}