Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Isolate computed fields return objects only if not referenced from other, non-isolated, objects #6543

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@
"useCalculatedVersion": true,
"prereleaseTemplate": "{tag}-{datetime}-{commit}"
},
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"updateInternalDependents": "always"
},
"ignore": ["website"]
}
5 changes: 5 additions & 0 deletions .changeset/serious-pants-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-tools/stitch': patch
---

Isolate computed fields return objects only if not referenced from other, non-isolated, objects
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ export function isolateComputedFieldsTransformer(
for (const type of returnTypes) {
const returnTypeMergeConfig = subschemaConfig.merge[type.name];

// isolate the object type only if it's not accessible from other, non-isolated, objects' fields
if (
Object.values(subschemaConfig.schema.getTypeMap())
.filter(isObjectType) // only objects
.filter(t => t !== type) // not this type
.filter(t => !isolatedSchemaTypes[t.name]) // not an isolated type
.find(t => Object.values(t.getFields()).find(f => getNamedType(f.type) === type)) // has a field returning this type
) {
continue;
}

if (isObjectType(type)) {
const returnTypeSelectionSet = returnTypeMergeConfig?.selectionSet;
if (returnTypeSelectionSet) {
Expand Down
88 changes: 88 additions & 0 deletions packages/stitch/tests/isolateComputedFieldsTransformer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,94 @@ type Mutation {
}"
`);
});
it.each([
{
name: 'type',
variant: /* GraphQL */ `
type SomeTypeWithDisappearingField {
otherField: String
disappearingField: SomeRequiredType
}
`,
},
{
name: 'required type',
variant: /* GraphQL */ `
type SomeTypeWithDisappearingField {
otherField: String
disappearingField: SomeRequiredType!
}
`,
},
{
name: 'array',
variant: /* GraphQL */ `
type SomeTypeWithDisappearingField {
otherField: String
disappearingField: [SomeRequiredType]
}
`,
},
{
name: 'required array',
variant: /* GraphQL */ `
type SomeTypeWithDisappearingField {
otherField: String
disappearingField: [SomeRequiredType]!
}
`,
},
{
name: 'required array and items',
variant: /* GraphQL */ `
type SomeTypeWithDisappearingField {
otherField: String
disappearingField: [SomeRequiredType!]!
}
`,
},
])('does not isolate $name referenced from other fields', async ({ variant }) => {
const [baseConfig, computedConfig] = isolateComputedFieldsTransformer({
schema: makeExecutableSchema({
typeDefs: /* GraphQL */ `
scalar _Any

union _Entity = User

type Query {
someResolver: SomeTypeWithDisappearingField
_entities(representations: [_Any!]!): _Entity
}

type SomeRequiredType {
id: String
}

${variant}

type User {
id: ID!
requiresField: SomeRequiredType
}
`,
}),
merge: {
User: {
selectionSet: '{ id }',
fields: {
requiresField: { selectionSet: '{ externalField }', computed: true },
},
fieldName: '_entities',
},
},
});

assertSome(baseConfig.merge);
expect(baseConfig.merge['SomeRequiredType']).toBeUndefined();

assertSome(computedConfig.merge);
expect(computedConfig.merge['SomeRequiredType']).toBeUndefined();
});
});

describe('with multiple entryPoints', () => {
Expand Down
Loading