Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
groq-builder
Advanced tools
Readme
groq-builder
A schema-aware, strongly-typed GROQ query builder.
It enables you to use auto-completion and type-checking for your GROQ queries.
From https://www.sanity.io/docs/groq:
"GROQ is Sanity's open-source query language. It's a powerful and intuitive language that's easy to learn. With GROQ you can describe exactly what information your application needs, join information from several sets of documents, and stitch together a very specific response with only the exact fields you need."
sanity.config.ts
for auto-completion and type-checkingimport { createGroqBuilder } from 'groq-builder';
import type { SchemaConfig } from './schema-config';
// ☝️ Note:
// Please see the "Schema Configuration" docs
// for an overview of this SchemaConfig type
const q = createGroqBuilder<SchemaConfig>()
const productsQuery = (
q.star
.filterByType('products')
.order('price desc')
.slice(0, 10)
.project(q => ({
name: true,
price: true,
slug: q.field("slug.current"),
imageUrls: q.field("images[]").deref().field("url")
}))
);
In the above query, ALL fields are strongly-typed, according to the Sanity schema defined in sanity.config.ts
!
'products'
, 'price desc'
, and 'images[]'
are strongly-typed, based on the matching field definitions.name
and price
are strongly-typed based on the fields of product
.This example generates the following GROQ query:
*[_type == "products"] | order(price desc)[0...10] {
name,
price,
"slug": slug.current,
"imageUrls": images[]->url
}
The above productsQuery
example generates the following results type:
import type { InferResultType } from 'groq-builder';
type ProductsQueryResult = InferResultType<typeof productsQuery>;
// 👆 Evaluates to the following:
type ProductsQueryResult = Array<{
name: string,
price: number,
slug: string,
imageUrls: Array<string>,
}>;
You can add custom runtime validation and/or parsing logic into your queries, using the validate
method.
The validate
function accepts a simple function:
const products = q.star.filterByType('products').project(q => ({
name: true,
price: true,
priceFormatted: q.field("price").validate(price => formatCurrency(price)),
}));
It is also compatible with Zod, and can take any Zod parser or validation logic:
const products = q.star.filterByType('products').project(q => ({
name: z.string(),
slug: ["slug.current", z.string().optional()],
price: q.field("price").validate(z.number().nonnegative()),
}));
The entry-point to this library is the createGroqBuilder<SchemaConfig>()
function, which returns a strongly-typed q
object. You must supply the SchemaConfig
type parameter, which lists all document types from your Sanity Schema.
There are 2 approaches for creating this Schema. You can specify the Schema manually, or you can auto-generate the types based on your sanity.config.ts
.
The simplest way to create a Sanity Schema is to manually specify the document types. Here's a working example:
import { createGroqBuilder } from './index';
declare const references: unique symbol;
type Product = {
_type: "product";
_id: string;
name: string;
price: number;
images: Array<{ width: number; height: number; url: string; }>;
category: { _type: "reference"; _ref: string; [references]: "category"; };
}
type Category = {
_type: "category";
_id: string;
name: string;
products: Array<{ _type: "reference"; _ref: string; [references]: "product"; }>;
}
export type SchemaConfig = {
documentTypes: Product | Category;
referenceSymbol: typeof references;
}
export const q = createGroqBuilder<SchemaConfig>();
The only complexity is how references are handled. In the Sanity data, the reference
object doesn't say what kind of document it's referencing. We have to add this type information, using a unique symbol. So above, we added [references]: "category"
to capture the reference type. This information is used by the .deref()
method to ensure we follow references correctly.
Fortunately, there is a way to automatically generate the Sanity Schema, using the Sanity configuration itself (sanity.config.ts
). This workflow has 2 steps: inferring types from the config, then copying the compiled types to your application.
sanity.config.ts
to infer the typesIn the repo with your Sanity configuration (sanity.config.ts
), use the @sanity-typed/types
library to augment your configuration code.
This is pretty easy, and involves:
from 'sanity';
to from '@sanity-typed/types'
as const
in a few places (according to the docs)Then, in your schema.config.ts
, you infer all document types by adding:
import { InferSchemaValues } from '@sanity-typed/types';
export type SanityValues = InferSchemaValues<typeof config>;
Now that you've got the SanityValues
type, you'll need to compile the types, and copy them to your application (where you're using groq-builder
).
Normally you could use tsc
to compile the types, and copy them over. However, there is a far better approach: use the ts-simplify
CLI tool to compile and simplify the types.
From your Sanity repo, run:
npx ts-simplify ./sanity.config.ts ./sanity-schema.ts
This generates a ./sanity-schema.ts
file that has no dependencies, just the Sanity types!
Move this file to your application (where you're using groq-builder
), and finally, glue it all together like so:
./q.ts
import { createGroqBuilder, ExtractDocumentTypes } from 'groq-builder';
import { referenced, SanityValues } from './sanity-schema'; // This is the generated file
export const q = createGroqBuilder<{
documentTypes: ExtractDocumentTypes<SanityValues>;
referenceSymbol: typeof referenced;
}>();
FAQs
A **schema-aware**, strongly-typed GROQ query builder. It enables you to use **auto-completion** and **type-checking** for your GROQ queries.
The npm package groq-builder receives a total of 574 weekly downloads. As such, groq-builder popularity was classified as not popular.
We found that groq-builder demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.