graphql-tools icon indicating copy to clipboard operation
graphql-tools copied to clipboard

Transform schema without removing pre-transformed nodes

Open ilonawong opened this issue 4 years ago • 4 comments

I am looking to transform a remote schema from something like this:

type Client {
  id: ID!
  account: Account
  name: String
}

type Account {
  id: ID!
  value: Int
}

to this:

type Client {
  id: ID!
  accountId: String // This being the Account's ID if it exists
  account: Account
  name: String
}

type Account {
  id: ID!
  value: Int
}

With all the different transforms I've tried, they remove the id from Account and put it in Client. However, this seems to break getting an Account of a Client because now the ID is gone.

So the resulting schema ends up looking like this:

type Client {
  id: ID!
  accountId: ID! // This is now always non-nullable because it takes the type of Account's ID
  account: Account
  name: String
}

type Account { // Account loses its ID 
  value: Int
}

I've tried using WrapFields and HoistFields and neither give the result I want. I also attempted to use TransformInterfaceFields (because Client is actually an interface) and MapFields, but either it doesn't seem to give what I want or I can't figure out how to use it.

Is what I'm looking for possible?

Thank you!

ilonawong avatar Jan 13 '21 16:01 ilonawong

Were you able to figure this out?

I think we need a version of HoistField that copies prior to hoisting, or maybe a generic transform that copies, and then you can do transforms: [new CopyField(...), new HoistField(...)]

Or did something else work for you?

yaacovCR avatar Jan 28 '21 18:01 yaacovCR

Nope, I ended up giving up on this :(

ilonawong avatar Jan 28 '21 19:01 ilonawong

@yaacovCR I ended up running into this issue and tried a couple of solutions to no avail. Like the original poster I'm also trying to hoist a field into an interface. Ideally having an API where an interface typeName can be passed would be ideal such as transforms: [new HoistField(<interfaceTypeName>, [...pathConfig], <newInterfaceField>) or a HoistInterfaceField transform if it needs to separate.

Originally I attempted transforms: getImplementingTypes('Entry', schema).map(typeName => new HoistField(typeName, ['sys', 'id'], 'id')). Where Entry is an interface with a field name sys with the type of type Sys { id: ID! }. This though didn't work as Sys.id gets removed by the first transform and isn't available on subsequent transforms.

I then tried modifying HoistField to replace removeObjectFields with selectObjectFields and then adding PruneSchema at the end of this of transforms. This created a valid schema but broke at runtime due to an exponential number of duplicate __typename fields being added to transformed request.

I did try using optimizeDocuments on the transformed request but had no luck with that approach.

jtmthf avatar May 23 '21 15:05 jtmthf

This sounds like a great challenge, but it’s been some time. Are you able to set up a very minimal breaking example as either PR with test or GitHub repo or code sandbox?

Thanks!!!

yaacovCR avatar May 24 '21 14:05 yaacovCR

Closing due to the missing reproduction. Feel free to create a new issue with a reproduction if the issue persists. Thanks!

ardatan avatar Mar 29 '23 05:03 ardatan