Splicing Keystone field resolvers into custom queries/mutations/types
See original GitHub issueWe can now define custom queries and mutations on a list and use custom GraphQL types for the output (#1503). This lets us do things like this…
const STAFF_SALES_QUERY = `
select store, employee, sum(sale_value) as "salesLastMonth"
from sales
where store = :store
and sale_date < date_trunc('month', now())
and sale_date >= date_trunc('month', now() - interval '1 month')
group by store, employee;
`;
keystone.createList('Store', {
// ...
queries: [
{
types: [
`type StaffSalesReportItem {
store: ID
employee: ID
salesLastMonth: Number
}`,
],
schema: 'StaffSalesReport(store: ID!): StaffSalesReportItem',
resolver: async (obj, { store }) => {
const { rows } = await keystone.adapters.KnexAdapter.knex.raw(STAFF_SALES_QUERY, { store });
return rows;
},
},
],
});
Super handy but, as above, the output types often relate to existing Keystone list. Since the whole thing is resolved with custom code there’s no way to drill into these fields and though they were relationship fields.
What we really want is for the type above to be closer to…
type StaffSalesReportItem {
store: Store
employee: Employee
salesLastMonth: Number
}
So we drill into the relationship and do queries like…
query {
StaffSalesReport ( store: "A8622468-9B70-41E1-97E3-620CF708CB0F" ) {
store { id name }
employee { id name email role { paygrade } startDate }
salesLastMonth
}
}
Note, we’re not just resolving the related item; we might be drilling into their relationships too. We want to hand off processing that entire part branch of the query. Regardless, I think this should be possible using they existing Keystone config.
Completely made up syntax and probably wrong but imagine something like this:
keystone.createList('Store', {
// ...
queries: [
{
types: [
// Note, now referencing existing List output types..
`type StaffSalesReportItem {
store: Store
employee: Employee
salesLastMonth: Number
}`,
],
schema: 'StaffSalesReport(store: ID!): StaffSalesReportItem',
resolver: async (obj, { store }, auth, info) => {
const { rows: items } = await keystone.adapters.KnexAdapter.knex.raw(STAFF_SALES_QUERY, { store });
await keystone.lists.stores.resolveItemsForGql({ items, path: '.store', auth, info });
await keystone.lists.employees.resolveItemsForGql({ items, path: '.employee', auth, info });
return items;
},
},
],
});
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:7 (4 by maintainers)
Top GitHub Comments
Using a hypothetical GraphQL schema extension API but using the real current Keystone API for getting the items, this is how you should solve this:
So what we need to do here is:
Hey @MadeByMike the example uses Knex but the tasks isn’t actually coupled to it so I’ve removed the tag. This is much more about GraphQL customisation.