Skip to content

Commit

Permalink
🐛 Fix abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
adbouygues committed Aug 21, 2024
1 parent 653b5ee commit 7e76dce
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 80 deletions.
80 changes: 45 additions & 35 deletions packages/graphql-mesh/patches/@graphql-tools+stitch+9.0.3.patch
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ index 5e752ad..3b487f5 100644
const currentNamedType = (0, graphql_1.getNamedType)(c.type);
if (finalNamedType.toString() !== currentNamedType.toString()) {
diff --git a/node_modules/@graphql-tools/stitch/cjs/typeCandidates.js b/node_modules/@graphql-tools/stitch/cjs/typeCandidates.js
index c915942..ae923fe 100644
index c915942..4b4a2e7 100644
--- a/node_modules/@graphql-tools/stitch/cjs/typeCandidates.js
+++ b/node_modules/@graphql-tools/stitch/cjs/typeCandidates.js
@@ -119,6 +119,33 @@ function buildTypes({ typeCandidates, directives, stitchingInfo, rootTypeNames,
Expand All @@ -33,9 +33,9 @@ index c915942..ae923fe 100644
+ otherCandidates.forEach((otherCandidate) => {
+ // Add fields from other candidates to the final interface
+ Object.keys(otherCandidate.type._fields).forEach(field => {
+ if (finalI.type._fields[field] === undefined) {
+ finalI.type._fields[field] = otherCandidate.type._fields[field];
+ }
+ if (finalI.type._fields[field] === undefined) {
+ finalI.type._fields[field] = otherCandidate.type._fields[field];
+ }
+ })
+ });
+ typeCandidates[typeName] = [finalI];
Expand All @@ -49,7 +49,7 @@ index c915942..ae923fe 100644
typeMap[typeName] = (0, mergeCandidates_js_1.mergeCandidates)(typeName, typeCandidates[typeName], typeMergingOptions);
}
else {
@@ -128,6 +155,61 @@ function buildTypes({ typeCandidates, directives, stitchingInfo, rootTypeNames,
@@ -128,6 +155,71 @@ function buildTypes({ typeCandidates, directives, stitchingInfo, rootTypeNames,
typeMap[typeName] = candidateSelector(typeCandidates[typeName]).type;
}
}
Expand All @@ -64,48 +64,58 @@ index c915942..ae923fe 100644
+ let duplicateFields = {};
+
+ typeInterfaces.forEach(i => {
+ const iFields = typeMap[i.name].getFields();
+ Object.keys(iFields).forEach(keyName => {
+ if (uniqueFields[keyName] === undefined) {
+ uniqueFields[keyName] = "defined";
+ }
+ else {
+ duplicateFields[keyName] = iFields[keyName];
+ }
+ })
+ const iFields = typeMap[i.name].getFields();
+ Object.keys(iFields).forEach(keyName => {
+ if (uniqueFields[keyName] === undefined) {
+ uniqueFields[keyName] = "defined";
+ }
+ else {
+ duplicateFields[keyName] = iFields[keyName];
+ }
+ })
+ })
+ // Ensure duplicate fields are consistent across implementations
+ Object.keys(duplicateFields).forEach(field => {
+ if (type.getFields()[field] !== undefined) {
+ type._fields[field] = duplicateFields[field];
+ }
+ typeInterfaces.forEach(i => {
+ const iFields = typeMap[i.name].getFields();
+ if (type.getFields()[field] !== undefined) {
+ type._fields[field] = duplicateFields[field];
+ }
+ typeInterfaces.forEach(i => {
+ const iFields = typeMap[i.name].getFields();
+
+ if (iFields[field] !== undefined) {
+ typeMap[i.name]._fields[field] = duplicateFields[field];
+ }
+ })
+ if (iFields[field] !== undefined) {
+ typeMap[i.name]._fields[field] = duplicateFields[field];
+ }
+ })
+ })
+ }
+ }
+ });
+ // Ensure object types implement all fields from their interfaces
+ Object.values(typeMap).forEach((type) => {
+ if (type.constructor.name === "GraphQLObjectType") {
+ const typeInterfaces = type.getInterfaces();
+ if (type.constructor.name === "GraphQLObjectType") {
+ const typeInterfaces = type.getInterfaces();
+
+ if (typeInterfaces.length !== 0) {
+ type._fields = type.getFields();
+ if (typeInterfaces.length !== 0) {
+ type._fields = type.getFields();
+
+ typeInterfaces.forEach(i => {
+ const iFields = typeMap[i.name].getFields();
+ Object.keys(iFields).forEach(keyName => {
+ type._fields[keyName] = iFields[keyName];
+ })
+ })
+ }
+ }
+ typeInterfaces.forEach(i => {
+ const iFields = typeMap[i.name].getFields();
+ Object.keys(iFields).forEach(keyName => {
+ type._fields[keyName] = iFields[keyName];
+ })
+ })
+ }
+ }
+ })
+ // Add a default type for all the interfaces
+ Object.values(typeMap).forEach((type) => {
+ if (type.constructor.name === "GraphQLInterfaceType") {
+ typeMap[`Default__${type.name}`] = new graphql_1.GraphQLObjectType({
+ name: `Default__${type.name}`,
+ fields: type.getFields(),
+ interfaces: [type]
+ })
+ }
+ })
+
return (0, utils_1.rewireTypes)(typeMap, directives);
Expand Down
20 changes: 10 additions & 10 deletions packages/graphql-mesh/patches/@omnigraph+json-schema+0.97.4.patch
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
diff --git a/node_modules/@omnigraph/json-schema/cjs/addRootFieldResolver.js b/node_modules/@omnigraph/json-schema/cjs/addRootFieldResolver.js
index 8006747..dfc6825 100644
old mode 100644
new mode 100755
index 8006747..f2af17c
--- a/node_modules/@omnigraph/json-schema/cjs/addRootFieldResolver.js
+++ b/node_modules/@omnigraph/json-schema/cjs/addRootFieldResolver.js
@@ -35,6 +35,23 @@ function addHTTPRootFieldResolver(schema, field, logger, globalFetch, { path, op
@@ -35,6 +35,21 @@ function addHTTPRootFieldResolver(schema, field, logger, globalFetch, { path, op
const interpolatedBaseUrl = string_interpolation_1.stringInterpolator.parse(endpoint, interpolationData);
const interpolatedPath = string_interpolation_1.stringInterpolator.parse(path, interpolationData);
let fullPath = (0, url_join_1.default)(interpolatedBaseUrl, interpolatedPath);
+ let subPath;
+ /**
+ * FIXME: This is a hack to follow link in the response
+ * In case where the root object contains several links,
+ * we need to follow the correct link which match the index of field in the path
+ */
+ if (root && root?.followsLink?.length) {
+
+ // HANDLE HATEOAS LINKS
+ if (root && root?.followLinks?.length) {
+ const index = info?.path?.key?.match(/_(\d+)_/)?.[1];
+ subPath = root.followsLink?.[index]?.followLink;
+ subPath = root.followLinks?.[index]?.followLink;
+ fullPath = interpolatedBaseUrl + subPath;
+ } else if (root && root.followLink) {
+ subPath = root.followLink;
+ fullPath = interpolatedBaseUrl + subPath;
+ }
+ if (root && !subPath) {
+ return
+ return;
+ }
+
const headers = {};
for (const headerName in globalOperationHeaders) {
const nonInterpolatedValue = globalOperationHeaders[headerName];
1 change: 1 addition & 0 deletions packages/graphql-mesh/utils/configFromSwaggers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export default class ConfigFromSwaggers {
}
})
}
this.interfacesWithChildren[schemaKey].push(`Default__${schemaKey.split('_')[0]}`)
}
})
return this.interfacesWithChildren
Expand Down
64 changes: 31 additions & 33 deletions packages/graphql-mesh/utils/generateTypeDefsAndResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,13 @@ export const generateTypeDefsAndResolversFromSwagger = (
// Filter for special keys such as 'x-links' and 'x-graphql-prefix-schema-with'
.filter(isSpecialKey)
.forEach(([key, value]) => {

// HANDLE SCHEMA PREFIXATION
if (key === 'x-graphql-prefix-schema-with') {
const schemaType = Object.keys(interfacesWithChildren).includes(schemaKey)
? 'interface'
: 'type'

// Add a prefixSchema directive to the type definition
typeDefs += `extend ${schemaType} ${schemaKey} @prefixSchema(prefix: "${value}") { dummy: String }\n`

// If it's an interface, add the dummy property to each of its children too
if (schemaType === 'interface') {
interfacesWithChildren[schemaKey].forEach((children) => {
Expand All @@ -67,7 +64,6 @@ export const generateTypeDefsAndResolversFromSwagger = (
})
}
}

// HANDLE HATEOAS LINKS PROCESSING
if (key === 'x-links') {
const trimedSchemaKey = trimLinks(schemaKey)
Expand Down Expand Up @@ -151,12 +147,14 @@ export const generateTypeDefsAndResolversFromSwagger = (
}`,

resolve: (root: any, args: any, context: any, info: any) => {
const hateoasLink: any = Object.entries(root._links).find(
(item) => item[0] === xLinkName
)?.[1]

if (hateoasLink?.href) {
root = { ...root, followLink: hateoasLink.href }
if (root._links) {
const hateoasLink: any = Object.entries(root._links).find(
(item) => item[0] === xLinkName
)?.[1]

if (hateoasLink?.href) {
root = { ...root, followLink: hateoasLink.href }
}
}

if (paramsToSend.length) {
Expand Down Expand Up @@ -223,12 +221,14 @@ export const generateTypeDefsAndResolversFromSwagger = (
}`,

resolve: (root: any, args: any, context: any, info: any) => {
const hateoasLink: any = Object.entries(root._links).find(
(item) => item[0] === xLinkName
)?.[1]
if (root._links) {
const hateoasLink: any = Object.entries(root._links).find(
(item) => item[0] === xLinkName
)?.[1]

if (hateoasLink?.href) {
root = { ...root, followLink: hateoasLink.href }
if (hateoasLink?.href) {
root = { ...root, followLink: hateoasLink.href }
}
}

if (paramsToSend.length) {
Expand Down Expand Up @@ -257,21 +257,23 @@ export const generateTypeDefsAndResolversFromSwagger = (

// Resolvers for _linksList and _actionsList
if (Object.keys(subResolver).length) {
subTypeDefs += /* GraphQL */ `_linksList: [LinkItem]\n`
subResolver['_linksList'] = {
selectionSet: /* GraphQL */ `
if (_linksItems !== '') {
subTypeDefs += /* GraphQL */ `_linksList: [LinkItem]\n`
subResolver['_linksList'] = {
selectionSet: /* GraphQL */ `
{
_links {
${_linksItems}
}
}`,
resolve: (root: any) => {
return Object.keys(root?._links || {})
.filter((key) => root._links[key]?.href)
.map((key) => ({
rel: key,
href: root._links[key]?.href
}))
resolve: (root: any) => {
return Object.keys(root?._links || {})
.filter((key) => root._links[key]?.href)
.map((key) => ({
rel: key,
href: root._links[key]?.href
}))
}
}
}
if (_actionsItems !== '') {
Expand Down Expand Up @@ -302,7 +304,7 @@ export const generateTypeDefsAndResolversFromSwagger = (
// Delete the additional typeDefs section if no new fields have been added
subTypeDefs = subTypeDefs.replace(`extend ${schemaType} ${trimedSchemaKey} {\n}\n`, '')

if (subTypeDefs !== "") {
if (subTypeDefs !== '') {
typeDefs += subTypeDefs
resolvers[trimedSchemaKey] = subResolver
}
Expand Down Expand Up @@ -336,16 +338,12 @@ export const generateTypeDefsAndResolversFromSwagger = (
}
})

// Interfaces need to have the additional '__resolveType' property
// Resolvers of interfaces need to have the additional '__resolveType' property
resolvers[trimedSchemaKey].__resolveType = (res, _, schema) => {
if (res.__typename) {
if (res.__typename && !interfacesWithChildren[res.__typename]) {
return res.__typename
}
const returnTypeName = schema.returnType.name
const parentVersion = returnTypeName.split('_')[returnTypeName.split('_').length - 1]
return parentVersion !== trimedSchemaKey
? `${interfacesWithChildren[schema.returnType.name][1]}_${parentVersion}`
: `${interfacesWithChildren[schema.returnType.name][1]}`
return `Default__${schema.returnType.name}`
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions patches/@graphql-tools+batch-execute+9.0.2.patch
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ index dfe8afc..b60987c 100644
info: requests[0].info,
operationType,
- rootValue: requests[0].rootValue,
+ // FIXME: Extend the rootValue with the followsLink to save followLink for all requests that are merged and executed in parallel
+ rootValue: { ...requests[0].rootValue, followsLink: requests.map((request) => ({ followLink: request.rootValue.followLink })) },
+ // Extend the rootValue with an array of the available links
+ rootValue: { ...requests[0].rootValue, followLinks: requests.map((request) => ({ followLink: request.rootValue.followLink })) },
};
}
exports.mergeRequests = mergeRequests;
12 changes: 12 additions & 0 deletions patches/graphql+16.8.1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/node_modules/graphql/jsutils/devAssert.js b/node_modules/graphql/jsutils/devAssert.js
index c40d406..c21c8ef 100644
--- a/node_modules/graphql/jsutils/devAssert.js
+++ b/node_modules/graphql/jsutils/devAssert.js
@@ -9,6 +9,6 @@ function devAssert(condition, message) {
const booleanCondition = Boolean(condition);

if (!booleanCondition) {
- throw new Error(message);
+ console.error(message);
}
}

0 comments on commit 7e76dce

Please sign in to comment.