Skip to content

Commit 5e8b2e4

Browse files
benjiejemgillam
andauthored
Release post for this next major beta! (#429)
* Beta2 release post * Add grafast logo * update thank you image * Sponsor thank you * add to navbar --------- Co-authored-by: Jem Gillam <6413628+jemgillam@users.noreply.github.com>
1 parent ef1fc11 commit 5e8b2e4

File tree

4 files changed

+900
-9
lines changed

4 files changed

+900
-9
lines changed

src/data/nav.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
}
1717
],
1818
"pages": [
19+
{
20+
"to": "/news/20250324-major-grafast-beta/",
21+
"title": "Major Grafast release: beta.21",
22+
"sectionId": "main"
23+
},
1924
{
2025
"to": "/news/20230803-postgraphile-v5-beta/",
2126
"title": "PostGraphile V5 public beta!",
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
---
2+
layout: post
3+
title: "Major Grafast beta: three down, one to go"
4+
date: 2025-03-24T17:00:00Z
5+
path: /news/20250324-major-grafast-beta/
6+
thumbnail: /images/news/grafast-wordmark-2023.svg
7+
thumbnailAlt: "A developer looks at her monitor while holding a cup of tea."
8+
tags: announcements, releases, grafast, postgraphile
9+
noToc: false
10+
11+
summary:
12+
"This release contains more than 3 months of work, and is a major step towards
13+
release readiness."
14+
---
15+
16+
_Announced 2025-03-24 by Benjie_
17+
18+
<p class='intro'>
19+
In the first Gra<em>fast</em> Working Group, we outlined 4 <em>major</em> issues in Gra<em>fast</em>
20+
that needed to be addressed before we could think about general release. With
21+
this release, 3 of these are now complete!
22+
</p>
23+
24+
- ✅⤵️ Global dependencies - solved via "unary" steps
25+
- ✅⤵️ Early exit - solved via "flags"
26+
- ✅🎉 **Eradicating eval - this release!**
27+
- 🤔🔜 Polymorphism
28+
29+
After 3 months of gruelling work, we're proud to announce that the third of
30+
these, eradicating eval, is now addressed with the launch of
31+
`grafast@0.1.1-beta.21` (used as the core execution engine in
32+
`postgraphile@5.0.0-beta.39`). Let's look into what that has meant.
33+
34+
## Input evaluation moved to runtime
35+
36+
Since the beginning, Gra*fast* has had the ability to add plan resolvers not
37+
just to fields, not just to arguments, but also to input object fields
38+
(including those within lists). This made Gra*fast*'s planning really ergonomic
39+
for things like nested filters, which was great for PostGraphile! But it turns
40+
out it's really problematic for certain shapes of input — planning would put
41+
constraints on the variables compatible with the plan, requiring potentially
42+
unlimited numbers of operation plans needing to be built for the same GraphQL
43+
document. Worse: for large input trees involving lists, the number of steps
44+
generated could be overwhelming, resulting in the deduplication phase taking
45+
excessive time.
46+
47+
One particular user example that could cause 4 minutes of planning time from
48+
just a 100kB input made it clear that we had overreached with using plan
49+
resolvers too deep into inputs; so we've scaled it back so that you can only add
50+
plan resolvers to fields and arguments, you can no longer attach `applyPlan` or
51+
`inputPlan` to input object fields. This was something that we used a lot
52+
internally (hence the huge time investment migrating away!), but very few people
53+
(no-one?) used externally so it was ripe for removal.
54+
55+
That problematic query that took 4 minutes to plan before? It now takes 1.1ms to
56+
plan, yielding a 200,000x speedup!
57+
58+
### What does this mean for my codebase?
59+
60+
Hopefully good things! Please update to the latest `@beta` of all the
61+
PostGraphile and/or Gra*fast* related modules you're using (including plugins)
62+
and for most users everything should work as before, only better.
63+
64+
I've outlined some of the most common changes you may need to make below, but if
65+
you are impacted by any other changes, please ask for help in the chat — AFAIK
66+
most of the other things that have had significant changes are used by almost
67+
no-one except me, so it doesn't make sense for me to invest time documenting it
68+
here. If you're curious, many items are documented in both the changelogs and
69+
the pull requests where the changes occurred.
70+
71+
#### Change `fieldArgs.get` to `fieldArgs.getRaw`
72+
73+
Because we've removed `inputPlan`, the `fieldArgs.get(key)` method is no more;
74+
instead use `fieldArgs.getRaw(key)` which is equivalent unless the inputs had
75+
plans (which they cannot any more).
76+
77+
#### Converting `applyPlan` and `inputPlan`
78+
79+
If your input object fields did have plan resolvers then instead of having
80+
Grafast automatically call them on each and every input field recursively at
81+
plan-time, we now have the `applyInput` and `bakedInput` steps that represent
82+
runtime application or transform of these inputs recursively via a single step
83+
in our plan diagram.
84+
85+
We've managed to make this new runtime system very similar in shape to the old
86+
plan-time system, so PostGraphile plugins don't need to change much — this was
87+
largely enabled by how closely we managed to get the Grafast plan syntax to the
88+
syntax of code you would normally write at runtime. The first change is to
89+
rename `applyPlan` to `apply`, and `inputPlan` to `baked`. From there, your code
90+
might just work straight away, or it might need some more small tweaks (e.g.
91+
`fieldArgs` is no longer present, it's been replaced with simply the runtime
92+
value of the current field).
93+
94+
#### No more `$step.eval*()`
95+
96+
The eval methods are now marked as internal so you will get TypeScript errors if
97+
you try and use them. They will likely be removed at some point after release,
98+
so you should be sure to migrate away from using them at your earliest
99+
opportunity. But you weren't using them anyway… right?
100+
101+
#### ExecutableStep renamed to Step
102+
103+
This one is more cosmetic…
104+
105+
Since we no longer have plan resolvers deep in inputs, we no longer have the
106+
`ModifierStep` system that was used for managing them (it's been replaced with
107+
`Modifier` which happens at runtime). Since we no longer have ModifierStep, we
108+
no longer need `BaseStep` to be separate from and inherited by `ExecutableStep`,
109+
so we've merged them. Since this is the base class for _all_ steps now, we've
110+
renamed it to simply `Step`.
111+
112+
_We have kept an <code>ExecutableStep</code> export for backwards
113+
compatibility._
114+
115+
## PostGraphile changes
116+
117+
In addition to the changes above that impact everything that uses Gra*fast*,
118+
here are some of the changes that specifically impact PostGraphile users.
119+
120+
### SQL generation moved to runtime
121+
122+
PostGraphile's various SQL-running steps like PgSelectStep now build their
123+
queries at runtime rather than plantime. They use the "builder" pattern, where
124+
much of the SQL query can be established at plan-time, but final tweaks can be
125+
applied at run-time (register tweaks via the `$pgSelect.apply($callback)`
126+
method) before the query is built.
127+
128+
### SQL efficiency increased
129+
130+
Since we have more information at run-time, our SQL queries were able to become
131+
even simpler, 10% smaller on average across our test suite! This nets us a
132+
modest performance improvement inside PostgreSQL, but the shift to runtime does
133+
cost us a little performance in the JS layer since queries now need to be built
134+
for every request, rather than once per plan. We're happy with this tradeoff;
135+
one of the core goals of PostGraphile V5 (and the motivation for Grafast in the
136+
first place) was to shift load from the PostgreSQL layer (which is non-trivial
137+
to scale) to the Node.js layer (which is easy to scale horizontally).
138+
139+
### Postgres Arrays now parse 5x faster
140+
141+
I've also [backported](https://github.com/bendrucker/postgres-array/pull/19)
142+
these [fixes](https://github.com/bendrucker/postgres-array/pull/20) into the
143+
`postgres-array` npm module for everyone that uses `pg` to benefit from.
144+
145+
### Easier to write SQL fragments
146+
147+
Added a new feature to `pg-sql2` that allows us to handle non-SQL parameter
148+
embeds with custom code, making it easier to write custom SQL, e.g. if a value
149+
is already coming from SQL you can embed it directly without having to invoke
150+
placeholder:
151+
152+
```diff
153+
const $fooId = $foo.get('id');
154+
-$pgSelect.where(sql`foo_id = ${$pgSelect.placeholder($fooId)}`);
155+
+$pgSelect.where(sql`foo_id = ${$fooId}`);
156+
```
157+
158+
We've also added the ability to embed dynamic SQL fragments that can be
159+
dependent on runtime values (these values must be unary, i.e. they must come
160+
from GraphQL field arguments or derivatives thereof):
161+
162+
```ts
163+
const $includeArchived = fieldArgs.getRaw("includeArchived");
164+
const $condition = lambda($includeArchived, includeArchived =>
165+
includeArchived ? sql.true : sql`is_archived is false`
166+
);
167+
$pgSelect.where($condition);
168+
```
169+
170+
## Additional changes
171+
172+
### makeGrafastSchema
173+
174+
- 🚨The structure of `makeGrafastSchema` as it relates to arguments and input
175+
object fields has changed a little; use TypeScript to guide you. I'm hoping
176+
this is the last change of its kind before release.
177+
- New shortcuts added for argument `applyPlan()` and input field `apply()`
178+
methods.
179+
- Trimmed a load of unnecessary exported code, such as empty objects and field
180+
resolvers that do the same as the default field resolver.
181+
- Fix bug in `makeGrafastSchema` that fails to build schema sometimes if a field
182+
uses a function shortcut rather than object definition.
183+
- Fix bug in `makeGrafastSchema` that sometimes doesn't allow defining input
184+
objects
185+
186+
🚨 If you use `graphile-export` to export your schema as executable code, be
187+
sure to regenerate your schemas as the old generated code could be
188+
misinterpreted by the new `makeGrafastSchema`.
189+
190+
### graphile-export
191+
192+
- Massively improved the executable code output from `graphile-export` in
193+
combination with the changes to `makeGrafastSchema` above.
194+
- PostGraphile's "kitchen sink" schema export code now outputs 37KLOC rather
195+
than 47KLOC - a significant reduction in complexity!
196+
197+
### Improved plan diagrams
198+
199+
- Plan diagrams now reveal (via `@s` text) if a step is meant to be streamed.
200+
- Constant steps improved.
201+
- `Object: null prototype` simplified to `§` in output.
202+
- Hoist steps during `optimize` phase.
203+
- We no longer render dependencies on the `undefined` constant, because it's
204+
messy and doesn't add value
205+
- We group when there are multiple dependencies to the same step from the same
206+
step, and label the line with the count instead.
207+
208+
### Step classes
209+
210+
When writing your own step classes:
211+
212+
- `ExecutionValue` has gained a new `.unaryValue()` method that returns the
213+
unary value for unary execution values, and throws an error for non-unary
214+
execution values. This is much safer than the previous `.at(0)` trick which
215+
did not assert that you were actually dealing with a unary execution value.
216+
- If you were using `@stream` (incremental delivery) and had written your own
217+
`Step` class with stream support, first of all: amazing! Please let me know
218+
you did that (_via email or [Discord](https://discord.gg/graphile)_)!
219+
Secondly, you'll need to either rename your `stream` function to `execute` or
220+
merge its code into your existing `execute` method if you have one. It turns
221+
out there wasn't much point in separating them, and you can confer a lot of
222+
benefit from merging them.
223+
224+
### Other Gra*fast* improvements
225+
226+
- Compatible mutation operations can now complete synchronously via
227+
`grafastSync()`
228+
- Fixes bug in input objects where keys that weren't set would still be present
229+
with value `undefined`
230+
- Fix bug in step caching relating to polymorphism
231+
- New `items()` conventional method for extracting the items from a collection
232+
(makes for easier compatibility with connections)
233+
- Error handling improved
234+
- Lists improved - especially error handling and deduplication logic; as well as
235+
allowing returning connection-capable steps in list positions
236+
- Optimization to Gra*fast*'s internal execution values, which are used heavily
237+
in hot paths.
238+
239+
### Thank you Sponsors
240+
241+
Gra*fast* and PostGraphile are crowd-funded open-source software, they rely on
242+
crowd-sourced funding from individuals and companies to keep advancing.
243+
244+
If your company benefits from Gra*fast*, PostGraphile or the wider Graphile
245+
suite, you should consider asking them to fund our work. By significantly
246+
reducing the amount of work needed to achieve business goals and reducing
247+
running costs, Graphile's software results in huge time and money savings for
248+
users. We encourage companies to contribute a portion of these savings back,
249+
enabling the projects to advance more rapidly, and result in even greater
250+
savings for your company.
251+
[Find out more about sponsorship here on our website](/sponsor/).
252+
253+
<div class="flex flex-wrap justify-around">
254+
<img alt="Cartoon Benjie and Jem send cartoon hearts up into the sky" src="/images/news/postgraphile-thankyou.svg" style="max-height: 300px" />
255+
</div>

0 commit comments

Comments
 (0)