v5: Safe way to rename / remove / relocate fields
v5: Safe way to rename / remove / relocate fields (e.g. move totalCount into aggregate.count for Hasura-style aggregates)
Hi 👋. I’m using PostGraphile v5 with @graphile/pg-aggregates and Grafast, and I’m trying to build a plugin that reshapes the entire schema for connection types to look more like Hasura’s aggregate API.
Concretely, for any GraphQL object type that:
- is backed by a
ConnectionStep(i.e.Self.extensions.grafast.assertStep.$$export.exportName === "ConnectionStep"), and - exposes one of the aggregate fields added by
@graphile/pg-aggregates(e.g.aggregates,aggregate,groupedAggregates),
I’d like to be able to:
-
Rename fields (e.g. rename a connection root field or
aggregates→aggregate). -
Remove fields at the connection level (e.g. hide
totalCount/countfrom the top level). -
Clone / relocate fields while preserving their Grafast plan (e.g. move
totalCountso that it is also available asaggregate.countinside the aggregate container).
The end goal is a Hasura-like shape such as:
foo_aggregate {
aggregate {
count
sum { ... }
avg { ... }
}
groupedAggregate { ... }
}
…where aggregate.count behaves exactly like the existing totalCount/count on the connection (same semantics, same plan), and ideally we can optionally drop the top-level totalCount field.
What I tried
I experimented with:
-
schema.hooks.GraphQLObjectType_fields(v5 hook API), and -
processSchema(...)post-build transformations, and - copying the
GraphQLField/GraphQLFieldConfigand/orextensions.grafastfrom the connection’stotalCountfield into the aggregate container type.
This “works” at the type level (the new aggregate.count field appears in the schema), but at runtime it tends to break the aggregate object resolution – aggregate becomes null – because the copied plan was written assuming the parent step is the connection step, not the aggregate step.
In other words, naïvely cloning the field or its plan isn’t safe without deeper knowledge of the internal Step graph.
Request
Would it be possible to have either:
-
A documented pattern / example plugin that shows how to:
- rename / hide fields on
ConnectionStep-backed types, and - expose a
countfield inside the aggregate container that reuses the existing connection-leveltotalCountlogic safely, or
- rename / hide fields on
-
A first-class option in
@graphile/pg-aggregates/ core that exposes a Hasura-styleaggregate.count(optionally also allowing the top-leveltotalCountto be removed), or -
A small API hook that lets a plugin get from the aggregate Step back to the underlying connection Step (so a custom
aggregate.countplan can delegate to the same logic astotalCountwithout relying on internal, undocumented assumptions)?
I’m specifically trying to avoid:
- casting everything to
anyand poking at private properties, and - brittle hacks that rely on internal Step structures that may change.
A supported way to do “rename / remove / relocate field while preserving its Grafast plan” for connection/aggregate types would make Hasura-style compatibility much easier to maintain.
Thanks a lot for any guidance or API hooks you can provide 🙏
Quick message because it's Saturday, and preface: I have never once used Hasura so don't know it's layout or anything. Sounds like you're pretty close!
One option is instead of just taking the plan from the aggregates field, what you might need is the plan from the connection field and the aggregates field; something like:
const connectionPlan = connectionField.extensions.grafast.plan
const aggregatesPlan = aggregatesField.extensions.grafast.plan
const newPlan = ($parent, fieldArgs) => {
const $connection = connectionPlan($parent, fieldArgs);
return aggregatesPlan($connection);
}
But it sounds like foo_aggregate is a weak form of a connection field with the nodes/edges/pageInfo removed... So just have foo_aggregate use the connection plan - it doesn't much matter that you're not using those other features. In fact, you could:
- rename the connection field to
foo_aggregateusing inflection - rename the return type from FooConnection to FooAggregates (or whatever Hasura uses) using inflection
- delete the fields you don't need from the connection type, like
nodes,edgesandpayloadInfo - rename
totalCounttocount(hopefully using inflection; not 100% sure if that one goes through an inflector or not)
You could also just write the plans yourself, they're not that complex. Have a look at the exported schema around specifically these fields.
Hey @zxpectre, how's it going? Can I offer any further guidance?