support for union types
Closed this issue ยท 10 comments
is there support for unions and/or interfaces? one of my api calls returns content
and content
is a union type that can return diff types of models.
Example desired query output:
{
vehicle {
... on Car {
name
isSedan
NumSeats
topSpeed
}
... on Scooter {
name
isElectric
numMiles
topSpeed
}
}
}
@bebraw / @toadkicker any ideas on Unions / Interfaces?
#11 will fix this =)
@toadkicker Can you give an example here for @albertalquisola use case?
You can basically attack this however you want by creating your own adapter. I'm guessing this is a conditional thing you want, and so one approach could change the adapter to look for a unions flag in the querybuilder options.
Thanks for being responsive @atulmy and @toadkicker. For my 2 cents, i'd love for the api to be something like this:
query({
operation: 'vehicles',
possibleTypes: [
{ name: 'Car', fields: [{ owner: ['firstName', 'lastName' ]}, 'name', 'isSedan', 'numSeats', 'topSpeed'] },
{ name: 'Scooter', fields: ['name', 'isElectric', 'numMiles', 'topSpeed'] },
],
});
// output
`
{
vehicles {
... on Car {
owner {
firstName
lastName
}
name
isSedan
NumSeats
topSpeed
}
... on Scooter {
name
isElectric
numMiles
topSpeed
}
}
}
`
I'll also look over the adapter pr as well and see how flexible it is
The idea is that the adapter maintains the same documented API that the query builder adheres to. A custom adapter is just a Javascript class that implements the query/mutation adapter interface. Another way to say it is the adapter is the engine of the output, and for the engine to work it needs to have the right inputs.
In @albertalquisola particular use case consider ...car
in your fields., and then creating a custom adapter (it can extend from the default one) that outputs unions based on ...
provided in there. Or even simpler don't worry about detecting it, just hard code it to use the custom adapter when called.
@toadkicker, I get the concept behind the interface adapter, but could you post a pseudocode example?
Can just make UnionAdapter
, and change from the default:
private operationTemplate() {
return `... on ${this.operation.charAt(0).toUpperCase() + this.operation.substring(1)} { ${Utils.queryFieldsMap(
this.fields
)} }`;
}
@albertalquisola let us know if the adapter example was of help
Not too pretty but it does the trick:
- Create a custom adapter for the type of operation you want (based on DefaultQueryAdapter in my case)
- Replace the imports accordingly:
// UnionQueryAdapter.ts
import Fields from 'gql-query-builder/build/Fields';
import IQueryBuilderOptions from 'gql-query-builder/build/IQueryBuilderOptions';
import OperationType from 'gql-query-builder/build/OperationType';
import Utils from 'gql-query-builder/build/Utils';
import IQueryAdapter from 'gql-query-builder/build/adapters/IQueryAdapter';
import VariableOptions from 'gql-query-builder/build/VariableOptions';
- Replace the
operationTemplate
method with the following:
// UnionQueryAdapter.ts
private operationTemplate(variables: VariableOptions | undefined) {
return `${this.operation} ${
variables ? Utils.queryDataNameAndArgumentMap(variables) : ''
} ${
this.fields && this.fields.length > 0
? `{ ${this.fields
.map((query: any) => `... on ${Object.keys(query)[0]} { ${
Utils.queryFieldsMap(query[Object.keys(query)[0]])
} }`)
.join(' ')} }`
: ''
}`;
}
- Call your union like this:
query({
operation: 'foobar',
fields: [{ Foo: ['foofoo'] }, { Bar: ['barbar'] }],
},
UnionQueryAdapter,
)
// Output
query {
views {
... on Foo {
foofoo
}
... on Bar {
barbar
}
}
}
Hope this helps some people that were struggling with unions like myself.
Note: this solution isn't 100% complete but it should help kickstart your union needs ๐
Edit: here's the full adapter file: UnionQueryAdapter.ts