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

introduce input object field transformers: Filter/Rename/TransformInputObjectFields #1551

Merged
merged 4 commits into from Jun 5, 2020

Conversation

yaacovCR
Copy link
Collaborator

This PR represents an initial attempt at transforming input fields to address #1058

It does enable filtering and renaming input fields, which can then be included as dedicated transforms.

But it doesn't enable (yet?) adding default values for filtered fields, because the specified input field node transformer only transforms existing field nodes, it does not provide a hook for adding new ones.

(It does let you return multiple input field nodes instead of one, which could be helpful, but only for expanding a known required field node into a required and optional, and this is not really helpful for the general case).

An option would be to allow an additional generic inputObjectTransformer function to be specified that could modify the entire object as desired vs creating a TransformInputType transform that might be better suited to this.

Feedback is welcome.

@theguild-bot
Copy link
Collaborator

theguild-bot commented May 28, 2020

The latest changes of this PR are available as alpha in npm: 6.0.8-alpha-9f8f3e5.0

Quickly update your package.json by running:

npx match-version @graphql-tools 6.0.8-alpha-9f8f3e5.0

@yaacovCR
Copy link
Collaborator Author

Note that this PR so far only attempts to transform arguments at schema build time, not at runtime, i.e. it does not provide access to the parent object or context when attempting to set default values on a filtered field.

Manipulation of arguments at resolve time can be set by specifying a custom delegating resolver. https://www.graphql-tools.com/docs/remote-schemas#wrapschemaschemaconfig

createProxyingResolver option for wrapSchema lets you do this programatically (instead of manually adding/overriding resolvers to the wrapped schema using addResolversToSchema)

However, it might be nice to have a way of within the TransformInputFields or TransformInputObject transforms be able to specify a function that also does the necessary transformation if the transformed input type is used within that resolver.

This kind of question is similar to the issues explored by the graphql-field-arguments-coercion and apollo-validation-directives packages. Might we be able to use graphql-field-arguments-coercion -- which uses more basic building blocks -- within the Transformers being attempted here?

yaacovCR added a commit that referenced this pull request Jun 3, 2020
= provide binding option to delegateToSchema

A Binding is a function that takes a delegationContext (just the relevant subset of options passed to delegateSchema) and produces the set of transforms used to actually delegate (i.e. that "binds" the fieldNodes from the sourceSchema to that of the targetSchema), this provides library users ability to completely customize delegation behavior, even on a per field level. These delegation transforms are the specified schema transforms, but also the additional delegation transforms that reduce friction between the source and target schemas, see below.

= export defaultBinding that enables:

(a) setting arguments after schema transformation = AddArgumentsAsVariables
(b) conversion of original result into object annotated with errors for easy return and use with defaultMergedResolver = CheckResultAndHandleErrors
(c) addition of required selectionSets for use when stitching = AddSelectionSetsByField/Type, AddFragmentsByField
(d) automatic filtering of fields not in target schema, useful for stitching and many other scenarios = FilterToSchema
(e) delegation from concrete types in source schema to abstract types in target schema = WrapConcreteTypes
(f) delegation from new abstract types in source schema (not found in target schema) to implementations within target schemas = ExpandAbstractTypes

= addition of internal Transformer class responsible for applying transforms

The Transformer class is constructed with a delegationContext and a binding function and uses them to produces the delegating transforms. The Transformer creates an individual transformationContext for each transform (for easy sharing of state between the transformRequest and transformResult methods, a new feature) and exposes transformRequest and transformResult methods that performs the individual transformations with the transformationContext, and the delegationContext, which gives the transformRequest and transformResult methods access to the overall state, including the original graphql context. These additional arguments may help enable advanced transforms such as specifying input fields in target schema not present or filtered from the source schema, see #1551.
yaacovCR added a commit that referenced this pull request Jun 4, 2020
= provide binding option to delegateToSchema

A Binding is a function that takes a delegationContext (just the relevant subset of options passed to delegateSchema) and produces the set of transforms used to actually delegate (i.e. that "binds" the fieldNodes from the sourceSchema to that of the targetSchema), this provides library users ability to completely customize delegation behavior, even on a per field level. These delegation transforms are the specified schema transforms, but also the additional delegation transforms that reduce friction between the source and target schemas, see below.

= export defaultBinding that enables:

(a) setting arguments after schema transformation = AddArgumentsAsVariables
(b) conversion of original result into object annotated with errors for easy return and use with defaultMergedResolver = CheckResultAndHandleErrors
(c) addition of required selectionSets for use when stitching = AddSelectionSetsByField/Type, AddFragmentsByField
(d) automatic filtering of fields not in target schema, useful for stitching and many other scenarios = FilterToSchema
(e) delegation from concrete types in source schema to abstract types in target schema = WrapConcreteTypes
(f) delegation from new abstract types in source schema (not found in target schema) to implementations within target schemas = ExpandAbstractTypes

= addition of internal Transformer class responsible for applying transforms

The Transformer class is constructed with a delegationContext and a binding function and uses them to produces the delegating transforms. The Transformer creates an individual transformationContext for each transform (for easy sharing of state between the transformRequest and transformResult methods, a new feature) and exposes transformRequest and transformResult methods that performs the individual transformations with arguments of the original request/result, the delegationContext, and the individual transformationContext, which gives the transformRequest and transformResult methods access to the overall state, including the original graphql context, as well as any additional state they want to set up. These additional arguments may help enable advanced transforms such as specifying input fields in target schema not present or filtered from the source schema, see #1551.
yaacovCR added a commit that referenced this pull request Jun 4, 2020
= provide binding option to delegateToSchema

A Binding is a function that takes a delegationContext (just the relevant subset of options passed to delegateSchema) and produces the set of transforms used to actually delegate (i.e. that "binds" the fieldNodes from the sourceSchema to that of the targetSchema), this provides library users ability to completely customize delegation behavior, even on a per field level. These delegation transforms are the specified schema transforms, but also the additional delegation transforms that reduce friction between the source and target schemas, see below.

= export defaultBinding that enables:

(a) setting arguments after schema transformation = AddArgumentsAsVariables
(b) conversion of original result into object annotated with errors for easy return and use with defaultMergedResolver = CheckResultAndHandleErrors
(c) addition of required selectionSets for use when stitching = AddSelectionSetsByField/Type, AddFragmentsByField
(d) automatic filtering of fields not in target schema, useful for stitching and many other scenarios = FilterToSchema
(e) delegation from concrete types in source schema to abstract types in target schema = WrapConcreteTypes
(f) delegation from new abstract types in source schema (not found in target schema) to implementations within target schemas = ExpandAbstractTypes

= addition of internal Transformer class responsible for applying transforms

The Transformer class is constructed with a delegationContext and a binding function and uses them to produces the delegating transforms. The Transformer creates an individual transformationContext for each transform (for easy sharing of state between the transformRequest and transformResult methods, a new feature) and exposes transformRequest and transformResult methods that performs the individual transformations with arguments of the original request/result, the delegationContext, and the individual transformationContext, which gives the transformRequest and transformResult methods access to the overall state, including the original graphql context, as well as any additional state they want to set up. These additional arguments may help enable advanced transforms such as specifying input fields in target schema not present or filtered from the source schema, see #1551.
yaacovCR added a commit that referenced this pull request Jun 4, 2020
= provide binding option to delegateToSchema

A Binding is a function that takes a delegationContext (just the relevant subset of options passed to delegateSchema) and produces the set of transforms used to actually delegate (i.e. that "binds" the fieldNodes from the sourceSchema to that of the targetSchema), this provides library users ability to completely customize delegation behavior, even on a per field level. These delegation transforms are the specified schema transforms, but also the additional delegation transforms that reduce friction between the source and target schemas, see below.

= export defaultBinding that enables:

(a) setting arguments after schema transformation = AddArgumentsAsVariables
(b) conversion of original result into object annotated with errors for easy return and use with defaultMergedResolver = CheckResultAndHandleErrors
(c) addition of required selectionSets for use when stitching = AddSelectionSetsByField/Type, AddFragmentsByField
(d) automatic filtering of fields not in target schema, useful for stitching and many other scenarios = FilterToSchema
(e) delegation from concrete types in source schema to abstract types in target schema = WrapConcreteTypes
(f) delegation from new abstract types in source schema (not found in target schema) to implementations within target schemas = ExpandAbstractTypes

= addition of internal Transformer class responsible for applying transforms

The Transformer class is constructed with a delegationContext and a binding function and uses them to produces the delegating transforms. The Transformer creates an individual transformationContext for each transform (for easy sharing of state between the transformRequest and transformResult methods, a new feature) and exposes transformRequest and transformResult methods that performs the individual transformations with arguments of the original request/result, the delegationContext, and the individual transformationContext, which gives the transformRequest and transformResult methods access to the overall state, including the original graphql context, as well as any additional state they want to set up. These additional arguments may help enable advanced transforms such as specifying input fields in target schema not present or filtered from the source schema, see #1551.
@yaacovCR
Copy link
Collaborator Author

yaacovCR commented Jun 4, 2020

We are now using the new delegationContext to allow the InputFieldNodeTransformer access to the graphql context -- and a InputObjectNodeTransformer that allows adding additional fields back.

@yaacovCR
Copy link
Collaborator Author

yaacovCR commented Jun 4, 2020

Next steps are to add the usual RenameInputObjectFields and FilterInputObjectFields transforms using this generic transform.

@yaacovCR yaacovCR marked this pull request as ready for review June 4, 2020 10:11
@yaacovCR yaacovCR requested a review from ardatan June 4, 2020 10:28
TransformInputFields => TransformInputObjectFields
@yaacovCR yaacovCR changed the title TransformInputFields introduce input field Transformers, FilterInputObjectFields, RenameInputObjectFields, and generic TransformInputObjectFields Jun 4, 2020
@yaacovCR yaacovCR changed the title introduce input field Transformers, FilterInputObjectFields, RenameInputObjectFields, and generic TransformInputObjectFields introduce input object field Transformers, Filter/Rename/TransformInputObjectFields Jun 4, 2020
@yaacovCR yaacovCR changed the title introduce input object field Transformers, Filter/Rename/TransformInputObjectFields introduce input object field transformers: Filter/Rename/TransformInputObjectFields Jun 4, 2020
@github-actions github-actions bot merged commit 35fd769 into master Jun 5, 2020
@github-actions github-actions bot deleted the transform-input-fields branch June 5, 2020 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants