@graphql-mesh/transform-federation 1.0.0-alpha-3fc47d119.0 → 1.0.0-alpha-20230420181317-a95037648
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.js +231 -0
- package/cjs/package.json +1 -0
- package/esm/index.js +228 -0
- package/package.json +30 -21
- package/typings/index.d.cts +12 -0
- package/{index.d.ts → typings/index.d.ts} +3 -2
- package/index.js +0 -156
- package/index.mjs +0 -154
package/cjs/index.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const dset_1 = require("dset");
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const types_js_1 = require("@apollo/subgraph/dist/types.js");
|
|
6
|
+
const string_interpolation_1 = require("@graphql-mesh/string-interpolation");
|
|
7
|
+
const utils_1 = require("@graphql-mesh/utils");
|
|
8
|
+
const utils_2 = require("@graphql-tools/utils");
|
|
9
|
+
const federationDirectives = [
|
|
10
|
+
'link',
|
|
11
|
+
'key',
|
|
12
|
+
'interfaceObject',
|
|
13
|
+
'extends',
|
|
14
|
+
'shareable',
|
|
15
|
+
'inaccessible',
|
|
16
|
+
'override',
|
|
17
|
+
'external',
|
|
18
|
+
'provides',
|
|
19
|
+
'requires',
|
|
20
|
+
'tag',
|
|
21
|
+
'composeDirective',
|
|
22
|
+
];
|
|
23
|
+
class FederationTransform {
|
|
24
|
+
constructor({ apiName, baseDir, config, importFn, }) {
|
|
25
|
+
this.noWrap = true;
|
|
26
|
+
this.apiName = apiName;
|
|
27
|
+
this.config = config;
|
|
28
|
+
this.baseDir = baseDir;
|
|
29
|
+
this.importFn = importFn;
|
|
30
|
+
}
|
|
31
|
+
transformSchema(schema, rawSource) {
|
|
32
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
33
|
+
rawSource.merge = {};
|
|
34
|
+
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
|
|
35
|
+
const queryType = schema.getQueryType();
|
|
36
|
+
const queryTypeFields = queryType.getFields();
|
|
37
|
+
for (const type of this.config.types) {
|
|
38
|
+
rawSource.merge[type.name] = {};
|
|
39
|
+
const typeObj = schema.getType(type.name);
|
|
40
|
+
typeObj.extensions = typeObj.extensions || {};
|
|
41
|
+
const typeDirectivesObj = (typeObj.extensions.directives =
|
|
42
|
+
typeObj.extensions.directives || {});
|
|
43
|
+
if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.key) {
|
|
44
|
+
typeDirectivesObj.key = type.config.key;
|
|
45
|
+
}
|
|
46
|
+
if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.shareable) {
|
|
47
|
+
typeDirectivesObj.shareable = type.config.shareable;
|
|
48
|
+
}
|
|
49
|
+
if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.extends) {
|
|
50
|
+
typeDirectivesObj.extends = type.config.extends;
|
|
51
|
+
}
|
|
52
|
+
const typeFieldObjs = typeObj.getFields();
|
|
53
|
+
if ((_e = type.config) === null || _e === void 0 ? void 0 : _e.fields) {
|
|
54
|
+
for (const field of type.config.fields) {
|
|
55
|
+
const typeField = typeFieldObjs[field.name];
|
|
56
|
+
if (typeField) {
|
|
57
|
+
typeField.extensions = typeField.extensions || {};
|
|
58
|
+
const directivesObj = (typeField.extensions.directives =
|
|
59
|
+
typeField.extensions.directives || {});
|
|
60
|
+
Object.assign(directivesObj, field.config);
|
|
61
|
+
}
|
|
62
|
+
rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
|
|
63
|
+
rawSource.merge[type.name].fields[field.name] =
|
|
64
|
+
rawSource.merge[type.name].fields[field.name] || {};
|
|
65
|
+
if (field.config.requires) {
|
|
66
|
+
rawSource.merge[type.name].fields[field.name].computed = true;
|
|
67
|
+
rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// If a field is a key field, it should be GraphQLID
|
|
72
|
+
if ((_f = type.config) === null || _f === void 0 ? void 0 : _f.key) {
|
|
73
|
+
let selectionSetContent = '';
|
|
74
|
+
for (const keyField of type.config.key) {
|
|
75
|
+
selectionSetContent += '\n';
|
|
76
|
+
selectionSetContent += keyField.fields || '';
|
|
77
|
+
}
|
|
78
|
+
if (selectionSetContent) {
|
|
79
|
+
rawSource.merge[type.name].selectionSet = `{ ${selectionSetContent} }`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
let resolveReference;
|
|
83
|
+
if ((_g = type.config) === null || _g === void 0 ? void 0 : _g.resolveReference) {
|
|
84
|
+
const resolveReferenceConfig = type.config.resolveReference;
|
|
85
|
+
if (typeof resolveReferenceConfig === 'string') {
|
|
86
|
+
const fn$ = (0, utils_1.loadFromModuleExportExpression)(resolveReferenceConfig, {
|
|
87
|
+
cwd: this.baseDir,
|
|
88
|
+
defaultExportName: 'default',
|
|
89
|
+
importFn: this.importFn,
|
|
90
|
+
});
|
|
91
|
+
resolveReference = (...args) => fn$.then(fn => fn(...args));
|
|
92
|
+
}
|
|
93
|
+
else if (typeof resolveReferenceConfig === 'function') {
|
|
94
|
+
resolveReference = resolveReferenceConfig;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
|
|
98
|
+
resolveReference = async (root, context, info) => {
|
|
99
|
+
const args = {};
|
|
100
|
+
for (const argName in resolveReferenceConfig.args) {
|
|
101
|
+
const argVal = string_interpolation_1.stringInterpolator.parse(resolveReferenceConfig.args[argName], {
|
|
102
|
+
root,
|
|
103
|
+
args,
|
|
104
|
+
context,
|
|
105
|
+
info,
|
|
106
|
+
env: process.env,
|
|
107
|
+
});
|
|
108
|
+
if (argVal) {
|
|
109
|
+
(0, dset_1.dset)(args, argName, argVal);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const result = await context[this.apiName].Query[queryField.name]({
|
|
113
|
+
root,
|
|
114
|
+
args,
|
|
115
|
+
context,
|
|
116
|
+
info,
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
...root,
|
|
120
|
+
...result,
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
rawSource.merge[type.name].resolve = resolveReference;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const entityTypes = [];
|
|
129
|
+
for (const typeName in rawSource.merge || {}) {
|
|
130
|
+
const type = schema.getType(typeName);
|
|
131
|
+
if ((0, graphql_1.isObjectType)(type)) {
|
|
132
|
+
entityTypes.push(type);
|
|
133
|
+
}
|
|
134
|
+
(0, dset_1.dset)(type, 'extensions.apollo.subgraph.resolveReference', rawSource.merge[typeName].resolve);
|
|
135
|
+
}
|
|
136
|
+
const schemaWithFederationQueryType = (0, utils_2.mapSchema)(schema, {
|
|
137
|
+
[utils_2.MapperKind.QUERY]: type => {
|
|
138
|
+
const config = type.toConfig();
|
|
139
|
+
return new graphql_1.GraphQLObjectType({
|
|
140
|
+
...config,
|
|
141
|
+
fields: {
|
|
142
|
+
...config.fields,
|
|
143
|
+
_entities: types_js_1.entitiesField,
|
|
144
|
+
_service: {
|
|
145
|
+
...types_js_1.serviceField,
|
|
146
|
+
resolve: (root, args, context, info) => ({
|
|
147
|
+
sdl: (0, utils_2.printSchemaWithDirectives)(info.schema),
|
|
148
|
+
}),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
const schemaWithUnionType = (0, utils_2.mapSchema)(schemaWithFederationQueryType, {
|
|
155
|
+
[utils_2.MapperKind.UNION_TYPE]: type => {
|
|
156
|
+
if (type.name === types_js_1.EntityType.name) {
|
|
157
|
+
return new graphql_1.GraphQLUnionType({
|
|
158
|
+
...types_js_1.EntityType.toConfig(),
|
|
159
|
+
types: entityTypes,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return type;
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
schemaWithUnionType.extensions = schemaWithUnionType.extensions || {};
|
|
166
|
+
const directivesObj = (schemaWithUnionType.extensions.directives =
|
|
167
|
+
schemaWithUnionType.extensions.directives || {});
|
|
168
|
+
const existingDirectives = schemaWithUnionType.getDirectives();
|
|
169
|
+
const filteredDirectives = existingDirectives.filter(directive => federationDirectives.includes(directive.name));
|
|
170
|
+
directivesObj.link = {
|
|
171
|
+
url: 'https://specs.apollo.dev/federation/' + (this.config.version || 'v2.0'),
|
|
172
|
+
import: filteredDirectives
|
|
173
|
+
.filter(({ name }) => name !== 'link')
|
|
174
|
+
.map(dirName => `@${dirName.name}`),
|
|
175
|
+
};
|
|
176
|
+
if (existingDirectives.length === filteredDirectives.length) {
|
|
177
|
+
return schemaWithUnionType;
|
|
178
|
+
}
|
|
179
|
+
return (0, utils_2.mapSchema)(schemaWithUnionType, {
|
|
180
|
+
[utils_2.MapperKind.DIRECTIVE]: directive => {
|
|
181
|
+
if (federationDirectives.includes(directive.name)) {
|
|
182
|
+
return directive;
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
},
|
|
186
|
+
[utils_2.MapperKind.OBJECT_TYPE]: type => {
|
|
187
|
+
var _a, _b;
|
|
188
|
+
return new graphql_1.GraphQLObjectType({
|
|
189
|
+
...type.toConfig(),
|
|
190
|
+
astNode: type.astNode && {
|
|
191
|
+
...type.astNode,
|
|
192
|
+
directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
|
|
193
|
+
},
|
|
194
|
+
extensions: {
|
|
195
|
+
...type.extensions,
|
|
196
|
+
directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
[utils_2.MapperKind.INTERFACE_TYPE]: type => {
|
|
201
|
+
var _a, _b;
|
|
202
|
+
return new graphql_1.GraphQLInterfaceType({
|
|
203
|
+
...type.toConfig(),
|
|
204
|
+
astNode: type.astNode && {
|
|
205
|
+
...type.astNode,
|
|
206
|
+
directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
|
|
207
|
+
},
|
|
208
|
+
extensions: {
|
|
209
|
+
...type.extensions,
|
|
210
|
+
directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
},
|
|
214
|
+
[utils_2.MapperKind.COMPOSITE_FIELD]: fieldConfig => {
|
|
215
|
+
var _a, _b;
|
|
216
|
+
return {
|
|
217
|
+
...fieldConfig,
|
|
218
|
+
astNode: fieldConfig.astNode && {
|
|
219
|
+
...fieldConfig.astNode,
|
|
220
|
+
directives: (_a = fieldConfig.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
|
|
221
|
+
},
|
|
222
|
+
extensions: {
|
|
223
|
+
...fieldConfig.extensions,
|
|
224
|
+
directives: Object.fromEntries(Object.entries(((_b = fieldConfig.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
exports.default = FederationTransform;
|
package/cjs/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { dset } from 'dset';
|
|
2
|
+
import { GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType, isObjectType, } from 'graphql';
|
|
3
|
+
import { entitiesField, EntityType, serviceField } from '@apollo/subgraph/dist/types.js';
|
|
4
|
+
import { stringInterpolator } from '@graphql-mesh/string-interpolation';
|
|
5
|
+
import { loadFromModuleExportExpression } from '@graphql-mesh/utils';
|
|
6
|
+
import { MapperKind, mapSchema, printSchemaWithDirectives } from '@graphql-tools/utils';
|
|
7
|
+
const federationDirectives = [
|
|
8
|
+
'link',
|
|
9
|
+
'key',
|
|
10
|
+
'interfaceObject',
|
|
11
|
+
'extends',
|
|
12
|
+
'shareable',
|
|
13
|
+
'inaccessible',
|
|
14
|
+
'override',
|
|
15
|
+
'external',
|
|
16
|
+
'provides',
|
|
17
|
+
'requires',
|
|
18
|
+
'tag',
|
|
19
|
+
'composeDirective',
|
|
20
|
+
];
|
|
21
|
+
export default class FederationTransform {
|
|
22
|
+
constructor({ apiName, baseDir, config, importFn, }) {
|
|
23
|
+
this.noWrap = true;
|
|
24
|
+
this.apiName = apiName;
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.baseDir = baseDir;
|
|
27
|
+
this.importFn = importFn;
|
|
28
|
+
}
|
|
29
|
+
transformSchema(schema, rawSource) {
|
|
30
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
31
|
+
rawSource.merge = {};
|
|
32
|
+
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
|
|
33
|
+
const queryType = schema.getQueryType();
|
|
34
|
+
const queryTypeFields = queryType.getFields();
|
|
35
|
+
for (const type of this.config.types) {
|
|
36
|
+
rawSource.merge[type.name] = {};
|
|
37
|
+
const typeObj = schema.getType(type.name);
|
|
38
|
+
typeObj.extensions = typeObj.extensions || {};
|
|
39
|
+
const typeDirectivesObj = (typeObj.extensions.directives =
|
|
40
|
+
typeObj.extensions.directives || {});
|
|
41
|
+
if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.key) {
|
|
42
|
+
typeDirectivesObj.key = type.config.key;
|
|
43
|
+
}
|
|
44
|
+
if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.shareable) {
|
|
45
|
+
typeDirectivesObj.shareable = type.config.shareable;
|
|
46
|
+
}
|
|
47
|
+
if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.extends) {
|
|
48
|
+
typeDirectivesObj.extends = type.config.extends;
|
|
49
|
+
}
|
|
50
|
+
const typeFieldObjs = typeObj.getFields();
|
|
51
|
+
if ((_e = type.config) === null || _e === void 0 ? void 0 : _e.fields) {
|
|
52
|
+
for (const field of type.config.fields) {
|
|
53
|
+
const typeField = typeFieldObjs[field.name];
|
|
54
|
+
if (typeField) {
|
|
55
|
+
typeField.extensions = typeField.extensions || {};
|
|
56
|
+
const directivesObj = (typeField.extensions.directives =
|
|
57
|
+
typeField.extensions.directives || {});
|
|
58
|
+
Object.assign(directivesObj, field.config);
|
|
59
|
+
}
|
|
60
|
+
rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
|
|
61
|
+
rawSource.merge[type.name].fields[field.name] =
|
|
62
|
+
rawSource.merge[type.name].fields[field.name] || {};
|
|
63
|
+
if (field.config.requires) {
|
|
64
|
+
rawSource.merge[type.name].fields[field.name].computed = true;
|
|
65
|
+
rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// If a field is a key field, it should be GraphQLID
|
|
70
|
+
if ((_f = type.config) === null || _f === void 0 ? void 0 : _f.key) {
|
|
71
|
+
let selectionSetContent = '';
|
|
72
|
+
for (const keyField of type.config.key) {
|
|
73
|
+
selectionSetContent += '\n';
|
|
74
|
+
selectionSetContent += keyField.fields || '';
|
|
75
|
+
}
|
|
76
|
+
if (selectionSetContent) {
|
|
77
|
+
rawSource.merge[type.name].selectionSet = `{ ${selectionSetContent} }`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
let resolveReference;
|
|
81
|
+
if ((_g = type.config) === null || _g === void 0 ? void 0 : _g.resolveReference) {
|
|
82
|
+
const resolveReferenceConfig = type.config.resolveReference;
|
|
83
|
+
if (typeof resolveReferenceConfig === 'string') {
|
|
84
|
+
const fn$ = loadFromModuleExportExpression(resolveReferenceConfig, {
|
|
85
|
+
cwd: this.baseDir,
|
|
86
|
+
defaultExportName: 'default',
|
|
87
|
+
importFn: this.importFn,
|
|
88
|
+
});
|
|
89
|
+
resolveReference = (...args) => fn$.then(fn => fn(...args));
|
|
90
|
+
}
|
|
91
|
+
else if (typeof resolveReferenceConfig === 'function') {
|
|
92
|
+
resolveReference = resolveReferenceConfig;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
|
|
96
|
+
resolveReference = async (root, context, info) => {
|
|
97
|
+
const args = {};
|
|
98
|
+
for (const argName in resolveReferenceConfig.args) {
|
|
99
|
+
const argVal = stringInterpolator.parse(resolveReferenceConfig.args[argName], {
|
|
100
|
+
root,
|
|
101
|
+
args,
|
|
102
|
+
context,
|
|
103
|
+
info,
|
|
104
|
+
env: process.env,
|
|
105
|
+
});
|
|
106
|
+
if (argVal) {
|
|
107
|
+
dset(args, argName, argVal);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const result = await context[this.apiName].Query[queryField.name]({
|
|
111
|
+
root,
|
|
112
|
+
args,
|
|
113
|
+
context,
|
|
114
|
+
info,
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
...root,
|
|
118
|
+
...result,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
rawSource.merge[type.name].resolve = resolveReference;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const entityTypes = [];
|
|
127
|
+
for (const typeName in rawSource.merge || {}) {
|
|
128
|
+
const type = schema.getType(typeName);
|
|
129
|
+
if (isObjectType(type)) {
|
|
130
|
+
entityTypes.push(type);
|
|
131
|
+
}
|
|
132
|
+
dset(type, 'extensions.apollo.subgraph.resolveReference', rawSource.merge[typeName].resolve);
|
|
133
|
+
}
|
|
134
|
+
const schemaWithFederationQueryType = mapSchema(schema, {
|
|
135
|
+
[MapperKind.QUERY]: type => {
|
|
136
|
+
const config = type.toConfig();
|
|
137
|
+
return new GraphQLObjectType({
|
|
138
|
+
...config,
|
|
139
|
+
fields: {
|
|
140
|
+
...config.fields,
|
|
141
|
+
_entities: entitiesField,
|
|
142
|
+
_service: {
|
|
143
|
+
...serviceField,
|
|
144
|
+
resolve: (root, args, context, info) => ({
|
|
145
|
+
sdl: printSchemaWithDirectives(info.schema),
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
const schemaWithUnionType = mapSchema(schemaWithFederationQueryType, {
|
|
153
|
+
[MapperKind.UNION_TYPE]: type => {
|
|
154
|
+
if (type.name === EntityType.name) {
|
|
155
|
+
return new GraphQLUnionType({
|
|
156
|
+
...EntityType.toConfig(),
|
|
157
|
+
types: entityTypes,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return type;
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
schemaWithUnionType.extensions = schemaWithUnionType.extensions || {};
|
|
164
|
+
const directivesObj = (schemaWithUnionType.extensions.directives =
|
|
165
|
+
schemaWithUnionType.extensions.directives || {});
|
|
166
|
+
const existingDirectives = schemaWithUnionType.getDirectives();
|
|
167
|
+
const filteredDirectives = existingDirectives.filter(directive => federationDirectives.includes(directive.name));
|
|
168
|
+
directivesObj.link = {
|
|
169
|
+
url: 'https://specs.apollo.dev/federation/' + (this.config.version || 'v2.0'),
|
|
170
|
+
import: filteredDirectives
|
|
171
|
+
.filter(({ name }) => name !== 'link')
|
|
172
|
+
.map(dirName => `@${dirName.name}`),
|
|
173
|
+
};
|
|
174
|
+
if (existingDirectives.length === filteredDirectives.length) {
|
|
175
|
+
return schemaWithUnionType;
|
|
176
|
+
}
|
|
177
|
+
return mapSchema(schemaWithUnionType, {
|
|
178
|
+
[MapperKind.DIRECTIVE]: directive => {
|
|
179
|
+
if (federationDirectives.includes(directive.name)) {
|
|
180
|
+
return directive;
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
},
|
|
184
|
+
[MapperKind.OBJECT_TYPE]: type => {
|
|
185
|
+
var _a, _b;
|
|
186
|
+
return new GraphQLObjectType({
|
|
187
|
+
...type.toConfig(),
|
|
188
|
+
astNode: type.astNode && {
|
|
189
|
+
...type.astNode,
|
|
190
|
+
directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
|
|
191
|
+
},
|
|
192
|
+
extensions: {
|
|
193
|
+
...type.extensions,
|
|
194
|
+
directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
[MapperKind.INTERFACE_TYPE]: type => {
|
|
199
|
+
var _a, _b;
|
|
200
|
+
return new GraphQLInterfaceType({
|
|
201
|
+
...type.toConfig(),
|
|
202
|
+
astNode: type.astNode && {
|
|
203
|
+
...type.astNode,
|
|
204
|
+
directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
|
|
205
|
+
},
|
|
206
|
+
extensions: {
|
|
207
|
+
...type.extensions,
|
|
208
|
+
directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
[MapperKind.COMPOSITE_FIELD]: fieldConfig => {
|
|
213
|
+
var _a, _b;
|
|
214
|
+
return {
|
|
215
|
+
...fieldConfig,
|
|
216
|
+
astNode: fieldConfig.astNode && {
|
|
217
|
+
...fieldConfig.astNode,
|
|
218
|
+
directives: (_a = fieldConfig.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
|
|
219
|
+
},
|
|
220
|
+
extensions: {
|
|
221
|
+
...fieldConfig.extensions,
|
|
222
|
+
directives: Object.fromEntries(Object.entries(((_b = fieldConfig.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
package/package.json
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphql-mesh/transform-federation",
|
|
3
|
-
"version": "1.0.0-alpha-
|
|
3
|
+
"version": "1.0.0-alpha-20230420181317-a95037648",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@graphql-mesh/types": "0.
|
|
7
|
-
"@graphql-mesh/utils": "1.0.0-alpha-
|
|
8
|
-
"graphql": "
|
|
6
|
+
"@graphql-mesh/types": "1.0.0-alpha-20230420181317-a95037648",
|
|
7
|
+
"@graphql-mesh/utils": "1.0.0-alpha-20230420181317-a95037648",
|
|
8
|
+
"@graphql-tools/utils": "^9.2.1",
|
|
9
|
+
"graphql": "*",
|
|
10
|
+
"tslib": "^2.4.0"
|
|
9
11
|
},
|
|
10
12
|
"dependencies": {
|
|
11
|
-
"@apollo/subgraph": "2.
|
|
12
|
-
"@graphql-
|
|
13
|
-
"@graphql-tools/
|
|
14
|
-
"@graphql-tools/
|
|
15
|
-
"
|
|
16
|
-
"
|
|
13
|
+
"@apollo/subgraph": "2.4.1",
|
|
14
|
+
"@graphql-mesh/string-interpolation": "0.4.4",
|
|
15
|
+
"@graphql-tools/delegate": "9.0.32",
|
|
16
|
+
"@graphql-tools/stitching-directives": "2.3.34",
|
|
17
|
+
"dset": "3.1.2",
|
|
18
|
+
"graphql-transform-federation": "2.2.0"
|
|
17
19
|
},
|
|
18
20
|
"repository": {
|
|
19
21
|
"type": "git",
|
|
@@ -21,21 +23,28 @@
|
|
|
21
23
|
"directory": "packages/transforms/federation"
|
|
22
24
|
},
|
|
23
25
|
"license": "MIT",
|
|
24
|
-
"main": "index.js",
|
|
25
|
-
"module": "index.
|
|
26
|
-
"typings": "index.d.ts",
|
|
26
|
+
"main": "cjs/index.js",
|
|
27
|
+
"module": "esm/index.js",
|
|
28
|
+
"typings": "typings/index.d.ts",
|
|
27
29
|
"typescript": {
|
|
28
|
-
"definition": "index.d.ts"
|
|
30
|
+
"definition": "typings/index.d.ts"
|
|
29
31
|
},
|
|
32
|
+
"type": "module",
|
|
30
33
|
"exports": {
|
|
31
34
|
".": {
|
|
32
|
-
"require":
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./typings/index.d.cts",
|
|
37
|
+
"default": "./cjs/index.js"
|
|
38
|
+
},
|
|
39
|
+
"import": {
|
|
40
|
+
"types": "./typings/index.d.ts",
|
|
41
|
+
"default": "./esm/index.js"
|
|
42
|
+
},
|
|
43
|
+
"default": {
|
|
44
|
+
"types": "./typings/index.d.ts",
|
|
45
|
+
"default": "./esm/index.js"
|
|
46
|
+
}
|
|
38
47
|
},
|
|
39
48
|
"./package.json": "./package.json"
|
|
40
49
|
}
|
|
41
|
-
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GraphQLSchema } from 'graphql';
|
|
2
|
+
import { MeshTransform, MeshTransformOptions, YamlConfig } from '@graphql-mesh/types';
|
|
3
|
+
import { SubschemaConfig } from '@graphql-tools/delegate';
|
|
4
|
+
export default class FederationTransform implements MeshTransform {
|
|
5
|
+
private apiName;
|
|
6
|
+
private config;
|
|
7
|
+
private baseDir;
|
|
8
|
+
private importFn;
|
|
9
|
+
noWrap: boolean;
|
|
10
|
+
constructor({ apiName, baseDir, config, importFn, }: MeshTransformOptions<YamlConfig.Transform['federation']>);
|
|
11
|
+
transformSchema(schema: GraphQLSchema, rawSource: SubschemaConfig): GraphQLSchema;
|
|
12
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { GraphQLSchema } from 'graphql';
|
|
2
|
-
import { MeshTransform,
|
|
2
|
+
import { MeshTransform, MeshTransformOptions, YamlConfig } from '@graphql-mesh/types';
|
|
3
3
|
import { SubschemaConfig } from '@graphql-tools/delegate';
|
|
4
4
|
export default class FederationTransform implements MeshTransform {
|
|
5
5
|
private apiName;
|
|
6
6
|
private config;
|
|
7
7
|
private baseDir;
|
|
8
8
|
private importFn;
|
|
9
|
-
|
|
9
|
+
noWrap: boolean;
|
|
10
|
+
constructor({ apiName, baseDir, config, importFn, }: MeshTransformOptions<YamlConfig.Transform['federation']>);
|
|
10
11
|
transformSchema(schema: GraphQLSchema, rawSource: SubschemaConfig): GraphQLSchema;
|
|
11
12
|
}
|
package/index.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const graphql = require('graphql');
|
|
4
|
-
const utils = require('@graphql-mesh/utils');
|
|
5
|
-
const transformSdl_js = require('graphql-transform-federation/dist/transform-sdl.js');
|
|
6
|
-
const types_js = require('@apollo/subgraph/dist/types.js');
|
|
7
|
-
const utils$1 = require('@graphql-tools/utils');
|
|
8
|
-
|
|
9
|
-
class FederationTransform {
|
|
10
|
-
constructor({ apiName, baseDir, config, importFn }) {
|
|
11
|
-
this.apiName = apiName;
|
|
12
|
-
this.config = config;
|
|
13
|
-
this.baseDir = baseDir;
|
|
14
|
-
this.importFn = importFn;
|
|
15
|
-
}
|
|
16
|
-
transformSchema(schema, rawSource) {
|
|
17
|
-
var _a, _b, _c, _d;
|
|
18
|
-
const federationConfig = {};
|
|
19
|
-
rawSource.merge = {};
|
|
20
|
-
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
|
|
21
|
-
const queryType = schema.getQueryType();
|
|
22
|
-
const queryTypeFields = queryType.getFields();
|
|
23
|
-
for (const type of this.config.types) {
|
|
24
|
-
rawSource.merge[type.name] = {};
|
|
25
|
-
const fields = {};
|
|
26
|
-
if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.fields) {
|
|
27
|
-
for (const field of type.config.fields) {
|
|
28
|
-
fields[field.name] = field.config;
|
|
29
|
-
rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
|
|
30
|
-
rawSource.merge[type.name].fields[field.name] = rawSource.merge[type.name].fields[field.name] || {};
|
|
31
|
-
if (field.config.requires) {
|
|
32
|
-
rawSource.merge[type.name].fields[field.name].computed = true;
|
|
33
|
-
rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// If a field is a key field, it should be GraphQLID
|
|
38
|
-
if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.keyFields) {
|
|
39
|
-
rawSource.merge[type.name].selectionSet = `{ ${type.config.keyFields.join(' ')} }`;
|
|
40
|
-
for (const fieldName of type.config.keyFields) {
|
|
41
|
-
const objectType = schema.getType(type.name);
|
|
42
|
-
if (objectType) {
|
|
43
|
-
const existingType = objectType.getFields()[fieldName].type;
|
|
44
|
-
objectType.getFields()[fieldName].type = graphql.isNonNullType(existingType)
|
|
45
|
-
? new graphql.GraphQLNonNull(graphql.GraphQLID)
|
|
46
|
-
: graphql.GraphQLID;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
let resolveReference;
|
|
51
|
-
if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.resolveReference) {
|
|
52
|
-
const resolveReferenceConfig = type.config.resolveReference;
|
|
53
|
-
if (typeof resolveReferenceConfig === 'string') {
|
|
54
|
-
const fn$ = utils.loadFromModuleExportExpression(resolveReferenceConfig, {
|
|
55
|
-
cwd: this.baseDir,
|
|
56
|
-
defaultExportName: 'default',
|
|
57
|
-
importFn: this.importFn,
|
|
58
|
-
});
|
|
59
|
-
resolveReference = (...args) => fn$.then(fn => fn(...args));
|
|
60
|
-
}
|
|
61
|
-
else if (typeof resolveReferenceConfig === 'function') {
|
|
62
|
-
resolveReference = resolveReferenceConfig;
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
|
|
66
|
-
const keyArg = resolveReferenceConfig.keyArg || queryField.args[0].name;
|
|
67
|
-
const keyField = type.config.keyFields[0];
|
|
68
|
-
const isBatch = graphql.isListType(queryField.args.find(arg => arg.name === keyArg));
|
|
69
|
-
resolveReference = async (root, context, info) => {
|
|
70
|
-
const result = await context[this.apiName].Query[queryField.name]({
|
|
71
|
-
root,
|
|
72
|
-
...(isBatch
|
|
73
|
-
? {
|
|
74
|
-
key: root[keyField],
|
|
75
|
-
argsFromKeys: (keys) => ({
|
|
76
|
-
[keyArg]: keys,
|
|
77
|
-
}),
|
|
78
|
-
}
|
|
79
|
-
: {
|
|
80
|
-
args: {
|
|
81
|
-
[keyArg]: root[keyField],
|
|
82
|
-
},
|
|
83
|
-
}),
|
|
84
|
-
context,
|
|
85
|
-
info,
|
|
86
|
-
});
|
|
87
|
-
return {
|
|
88
|
-
...root,
|
|
89
|
-
...result,
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
rawSource.merge[type.name].resolve = resolveReference;
|
|
94
|
-
}
|
|
95
|
-
federationConfig[type.name] = {
|
|
96
|
-
...type.config,
|
|
97
|
-
resolveReference,
|
|
98
|
-
fields,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
const entityTypes = Object.fromEntries(Object.entries(federationConfig)
|
|
103
|
-
.filter(([, { keyFields }]) => keyFields === null || keyFields === void 0 ? void 0 : keyFields.length)
|
|
104
|
-
.map(([objectName]) => {
|
|
105
|
-
const type = schema.getType(objectName);
|
|
106
|
-
if (!graphql.isObjectType(type)) {
|
|
107
|
-
throw new Error(`Type "${objectName}" is not an object type and can't have a key directive`);
|
|
108
|
-
}
|
|
109
|
-
return [objectName, type];
|
|
110
|
-
}));
|
|
111
|
-
const hasEntities = !!Object.keys(entityTypes).length;
|
|
112
|
-
const sdlWithFederationDirectives = transformSdl_js.addFederationAnnotations(utils$1.printSchemaWithDirectives(schema), federationConfig);
|
|
113
|
-
const schemaWithFederationQueryType = utils$1.mapSchema(schema, {
|
|
114
|
-
[utils$1.MapperKind.QUERY]: type => {
|
|
115
|
-
const config = type.toConfig();
|
|
116
|
-
return new graphql.GraphQLObjectType({
|
|
117
|
-
...config,
|
|
118
|
-
fields: {
|
|
119
|
-
...config.fields,
|
|
120
|
-
...(hasEntities && {
|
|
121
|
-
_entities: types_js.entitiesField,
|
|
122
|
-
_service: {
|
|
123
|
-
...types_js.serviceField,
|
|
124
|
-
resolve: () => ({ sdl: sdlWithFederationDirectives }),
|
|
125
|
-
},
|
|
126
|
-
}),
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
const schemaWithUnionType = utils$1.mapSchema(schemaWithFederationQueryType, {
|
|
132
|
-
[utils$1.MapperKind.UNION_TYPE]: type => {
|
|
133
|
-
if (type.name === types_js.EntityType.name) {
|
|
134
|
-
return new graphql.GraphQLUnionType({
|
|
135
|
-
...types_js.EntityType.toConfig(),
|
|
136
|
-
types: Object.values(entityTypes),
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return type;
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
// Not using transformSchema since it will remove resolveReference
|
|
143
|
-
Object.entries(federationConfig).forEach(([objectName, currentFederationConfig]) => {
|
|
144
|
-
if (currentFederationConfig.resolveReference) {
|
|
145
|
-
const type = schemaWithUnionType.getType(objectName);
|
|
146
|
-
if (!graphql.isObjectType(type)) {
|
|
147
|
-
throw new Error(`Type "${objectName}" is not an object type and can't have a resolveReference function`);
|
|
148
|
-
}
|
|
149
|
-
type.resolveObject = currentFederationConfig.resolveReference;
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
return schemaWithUnionType;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
module.exports = FederationTransform;
|
package/index.mjs
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { isNonNullType, GraphQLNonNull, GraphQLID, isListType, isObjectType, GraphQLObjectType, GraphQLUnionType } from 'graphql';
|
|
2
|
-
import { loadFromModuleExportExpression } from '@graphql-mesh/utils';
|
|
3
|
-
import { addFederationAnnotations } from 'graphql-transform-federation/dist/transform-sdl.js';
|
|
4
|
-
import { entitiesField, serviceField, EntityType } from '@apollo/subgraph/dist/types.js';
|
|
5
|
-
import { printSchemaWithDirectives, mapSchema, MapperKind } from '@graphql-tools/utils';
|
|
6
|
-
|
|
7
|
-
class FederationTransform {
|
|
8
|
-
constructor({ apiName, baseDir, config, importFn }) {
|
|
9
|
-
this.apiName = apiName;
|
|
10
|
-
this.config = config;
|
|
11
|
-
this.baseDir = baseDir;
|
|
12
|
-
this.importFn = importFn;
|
|
13
|
-
}
|
|
14
|
-
transformSchema(schema, rawSource) {
|
|
15
|
-
var _a, _b, _c, _d;
|
|
16
|
-
const federationConfig = {};
|
|
17
|
-
rawSource.merge = {};
|
|
18
|
-
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
|
|
19
|
-
const queryType = schema.getQueryType();
|
|
20
|
-
const queryTypeFields = queryType.getFields();
|
|
21
|
-
for (const type of this.config.types) {
|
|
22
|
-
rawSource.merge[type.name] = {};
|
|
23
|
-
const fields = {};
|
|
24
|
-
if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.fields) {
|
|
25
|
-
for (const field of type.config.fields) {
|
|
26
|
-
fields[field.name] = field.config;
|
|
27
|
-
rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
|
|
28
|
-
rawSource.merge[type.name].fields[field.name] = rawSource.merge[type.name].fields[field.name] || {};
|
|
29
|
-
if (field.config.requires) {
|
|
30
|
-
rawSource.merge[type.name].fields[field.name].computed = true;
|
|
31
|
-
rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
// If a field is a key field, it should be GraphQLID
|
|
36
|
-
if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.keyFields) {
|
|
37
|
-
rawSource.merge[type.name].selectionSet = `{ ${type.config.keyFields.join(' ')} }`;
|
|
38
|
-
for (const fieldName of type.config.keyFields) {
|
|
39
|
-
const objectType = schema.getType(type.name);
|
|
40
|
-
if (objectType) {
|
|
41
|
-
const existingType = objectType.getFields()[fieldName].type;
|
|
42
|
-
objectType.getFields()[fieldName].type = isNonNullType(existingType)
|
|
43
|
-
? new GraphQLNonNull(GraphQLID)
|
|
44
|
-
: GraphQLID;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
let resolveReference;
|
|
49
|
-
if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.resolveReference) {
|
|
50
|
-
const resolveReferenceConfig = type.config.resolveReference;
|
|
51
|
-
if (typeof resolveReferenceConfig === 'string') {
|
|
52
|
-
const fn$ = loadFromModuleExportExpression(resolveReferenceConfig, {
|
|
53
|
-
cwd: this.baseDir,
|
|
54
|
-
defaultExportName: 'default',
|
|
55
|
-
importFn: this.importFn,
|
|
56
|
-
});
|
|
57
|
-
resolveReference = (...args) => fn$.then(fn => fn(...args));
|
|
58
|
-
}
|
|
59
|
-
else if (typeof resolveReferenceConfig === 'function') {
|
|
60
|
-
resolveReference = resolveReferenceConfig;
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
|
|
64
|
-
const keyArg = resolveReferenceConfig.keyArg || queryField.args[0].name;
|
|
65
|
-
const keyField = type.config.keyFields[0];
|
|
66
|
-
const isBatch = isListType(queryField.args.find(arg => arg.name === keyArg));
|
|
67
|
-
resolveReference = async (root, context, info) => {
|
|
68
|
-
const result = await context[this.apiName].Query[queryField.name]({
|
|
69
|
-
root,
|
|
70
|
-
...(isBatch
|
|
71
|
-
? {
|
|
72
|
-
key: root[keyField],
|
|
73
|
-
argsFromKeys: (keys) => ({
|
|
74
|
-
[keyArg]: keys,
|
|
75
|
-
}),
|
|
76
|
-
}
|
|
77
|
-
: {
|
|
78
|
-
args: {
|
|
79
|
-
[keyArg]: root[keyField],
|
|
80
|
-
},
|
|
81
|
-
}),
|
|
82
|
-
context,
|
|
83
|
-
info,
|
|
84
|
-
});
|
|
85
|
-
return {
|
|
86
|
-
...root,
|
|
87
|
-
...result,
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
rawSource.merge[type.name].resolve = resolveReference;
|
|
92
|
-
}
|
|
93
|
-
federationConfig[type.name] = {
|
|
94
|
-
...type.config,
|
|
95
|
-
resolveReference,
|
|
96
|
-
fields,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const entityTypes = Object.fromEntries(Object.entries(federationConfig)
|
|
101
|
-
.filter(([, { keyFields }]) => keyFields === null || keyFields === void 0 ? void 0 : keyFields.length)
|
|
102
|
-
.map(([objectName]) => {
|
|
103
|
-
const type = schema.getType(objectName);
|
|
104
|
-
if (!isObjectType(type)) {
|
|
105
|
-
throw new Error(`Type "${objectName}" is not an object type and can't have a key directive`);
|
|
106
|
-
}
|
|
107
|
-
return [objectName, type];
|
|
108
|
-
}));
|
|
109
|
-
const hasEntities = !!Object.keys(entityTypes).length;
|
|
110
|
-
const sdlWithFederationDirectives = addFederationAnnotations(printSchemaWithDirectives(schema), federationConfig);
|
|
111
|
-
const schemaWithFederationQueryType = mapSchema(schema, {
|
|
112
|
-
[MapperKind.QUERY]: type => {
|
|
113
|
-
const config = type.toConfig();
|
|
114
|
-
return new GraphQLObjectType({
|
|
115
|
-
...config,
|
|
116
|
-
fields: {
|
|
117
|
-
...config.fields,
|
|
118
|
-
...(hasEntities && {
|
|
119
|
-
_entities: entitiesField,
|
|
120
|
-
_service: {
|
|
121
|
-
...serviceField,
|
|
122
|
-
resolve: () => ({ sdl: sdlWithFederationDirectives }),
|
|
123
|
-
},
|
|
124
|
-
}),
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
const schemaWithUnionType = mapSchema(schemaWithFederationQueryType, {
|
|
130
|
-
[MapperKind.UNION_TYPE]: type => {
|
|
131
|
-
if (type.name === EntityType.name) {
|
|
132
|
-
return new GraphQLUnionType({
|
|
133
|
-
...EntityType.toConfig(),
|
|
134
|
-
types: Object.values(entityTypes),
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
return type;
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
// Not using transformSchema since it will remove resolveReference
|
|
141
|
-
Object.entries(federationConfig).forEach(([objectName, currentFederationConfig]) => {
|
|
142
|
-
if (currentFederationConfig.resolveReference) {
|
|
143
|
-
const type = schemaWithUnionType.getType(objectName);
|
|
144
|
-
if (!isObjectType(type)) {
|
|
145
|
-
throw new Error(`Type "${objectName}" is not an object type and can't have a resolveReference function`);
|
|
146
|
-
}
|
|
147
|
-
type.resolveObject = currentFederationConfig.resolveReference;
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
return schemaWithUnionType;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export default FederationTransform;
|