Fragments
A "fragment" is a projection that's reusable. Fragments can be used across multiple queries, and can be easily extended or combined.
A "fragment" is just a useful
GroqD
concept; it is not an actual feature ofGROQ
.
Creating Fragments
When creating a fragment, you first specify the type of the fragment, using either q.fragment<T>()
or q.fragmentForType<"...">()
.
Then you call the .project(...)
method to select the appropriate fields. See the Projections documentation for details on this syntax.
q.fragmentForType<"type">()
Creates a fragment for a Document, based on the document type.
const productFragment = q.fragmentForType<"product">().project(sub => ({
name: q.string(),
price: q.number(),
images: sub.field("images[]").deref().project({
url: q.string(),
}),
}))
q.fragment<T>()
Creates a fragment for any type you specify. This is useful for inline types that do not have a top-level document type.
const keyValueFragment = q.fragment<{ key: string, value: number }>().project({
key: q.string(),
value: q.number(),
})
Using Fragments
Fragments are just plain objects, so they can be passed directly to .project(frag)
, or they can be spread like .project({ ...frag })
.
In a Query
Pass the fragment directly to .project
:
q.star.filterByType("product").project(productFragment)
// GROQ: *[_type == "product"]{
// name,
// price,
// "images": images[]->{ url }
// }
Or you can spread the fragment to extend it:
q.star.filterByType("product").project(sub => ({
...productFragment,
category: sub.field("category").deref().field("title"),
}))
Extending Fragments
Simply use the "spread" operator inside a projection:
const productDetailsFragment = q.fragmentForType<"product">().project(sub => ({
...productFragment,
category: sub.field("category").deref().field("title"),
}))
Combining Fragments
Multiple fragments can be combined using the spread operator:
const productColors = q.fragmentForType<"product">().project(sub => ({
colors: sub.field("colors[]").deref().field("name"),
}));
const productWithColors = q.fragmentForType<"product">().project({
...productFragment,
...productColors,
})
Extracting the Type
It's usually very useful to extract the type of a fragment, so you can consume it in various places.
This can be done via InferFragmentType<typeof frag>
:
import { InferFragmentType } from "groqd";
type ProductFragment = InferFragmentType<typeof productFragment>
// { name: string, price: number, images: Array<{ url }> }