In the first Grafast Working Group, we outlined 4 major issues in Grafast that needed to be addressed before we could think about general release. The fourth, and final, epic has now been solved!
- ✅ Global dependencies — solved via “unary” steps
- ✅ Early exit — solved via “flags”
- ✅ Eradicating eval
- ✅ Polymorphism — this release!
Grafast is the cutting-edge GraphQL planning and execution engine which PostGraphile uses, allowing it to build much more efficient SQL queries than PostGraphile V4 could achieve, whilst also significantly expanding the capabilities of the system - not to mention solving some longstanding issues!
Polymorphism epic achieved
In previous versions of Grafast there was the possibility of exponential plan branching due to the naive method of resolution of abstract types.
By moving the responsibility of polymorphic resolution from field plan resolvers into the abstract types themselves, we’ve centralized this logic, simplified field plan resolvers, and unlocked more optimization opportunities and greater execution efficiency. Polymorphic branches in one layer are now merged into a single “combined” step before planning the next level of polymorphism.
getPetIds
and getServiceAnimals
both fetch an Animal
ID and so they are combined together in order to fetch all of the required Animals by their IDs. Once the IDs are fetched, the nodes can branch out to the different Animal types.Users of PostGraphile’s Postgres-based polymorphism should not need to take any action to benefit from these changes, and may notice that their SQL queries are now slightly smaller.
TypeDefs / plans overhaul
In order to make the libraries more type safe, makeGrafastSchema
(from
grafast
) and makeExtendSchemaPlugin
(from postgraphile/utils
) have
deprecated the typeDefs
/plans
pattern since plans
(like resolvers
in the
traditional format) ended up being a mish-mash of lots of different types
(objects, scalars, enums, etc) and __
-prefixed fields (__resolveType
,
__isTypeOf
, etc) for methods on the type itself.
Going forwards, the configuration should be split into typeDefs
with
objects
, interfaces
, unions
, inputObjects
, scalars
and enums
as
appropriate. Type-level properties such as
resolveType
/isTypeOf
/planType
/scope
/etc are no longer prefixed with __
and, to avoid conflicts with these type-level properties, object and input
object fields should be specified inside a new plans
property and enum values
within the new values
property.
The old pattern will still work (this is not a breaking change), but we recommend moving to the new shape and will use it for all of our examples in the documentation from now on.
Migration is quite straightforward:
Add new top-level properties. Add
objects
,interfaces
,unions
,inputObjects
,scalars
, andenums
as top level properties alongsidetypeDefs
andplans
. Each should be an empty object. You can skip any where you’re not defining types of that kind.Split definitions based on type kind. For each type defined in
plans
move it into the appropriate new object (based on keyword defining the type; i.e.type
→objects
,interface
→interfaces
,union
→unions
,input object
→inputObjects
,scalar
→scalars
,enum
→enums
).Move field plans into nested
plans: {...}
object. For each type defined in the newobjects
andinputObjects
objects: create aplans: { ... }
entry inside the type and move all fields (anything not prefixed with__
) inside this new (nested) property.Move enum values into nested
values: {...}
object. For each type defined in the newenums
object: create avalues: { ... }
entry inside the type and move all values (anything not prefixed with__
) inside this new (nested) property.Remove
__
prefixes. For each type acrossobjects
/interfaces
/unions
/interfaceObjects
/scalars
andenums
: remove the__
prefix from any methods/properties.
Example:
typeDefs: ...,
-plans: {
+objects: {
User: {
- __isTypeOf(v) {
+ isTypeOf(v) {
return v.username != null;
},
plans: {
fieldName($source, fieldArgs) {
// ...
},
+ },
},
+},
+interfaces: {,
MyInterface: {
- __resolveType($specifier) {
+ resolveType($specifier) {
// ...
}
}
+},
+enums: {
MyEnum: {
ONE
TWO
THREE
}
},
(Aside: we pasted the markdown version of these instructions into ChatGPT and it managed to convert a number of plugins perfectly! YMMV.)
And more besides...
In reaching this epic milestone, we have bumped the minimum version of node.js to Node 22 (the latest LTS); we have also found and fixed a number of other issues both in PostGraphile and the wider Graphile suite, you can see a full list at graphile.org.
Thank you Sponsors
PostGraphile is crowd-funded open-source software, it relies on crowd-sourced funding from individuals and companies to keep advancing.
If your company benefits from PostGraphile, Grafast or the wider Graphile suite, you should consider asking them to fund our work. By significantly reducing the amount of work needed to achieve business goals and reducing running costs, Graphile’s software results in huge time and money savings for users. We encourage companies to contribute a portion of these savings back, enabling the projects to advance more rapidly, and result in even greater savings for your company. Find out more about sponsorship on graphile.org.