@danteissaias/groq-builder
TypeScript icon, indicating that this package has built-in type declarations

0.9.2 • Public • Published

groq-builder

A schema-aware, strongly-typed GROQ query builder.
It enables you to build GROQ queries using auto-completion, type-checking, and runtime validation.

What is 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."

Features

  • Schema-aware - uses your sanity.config.ts schema for auto-completion and type-checking.
  • Strongly-typed - query results are strongly typed, based on your Sanity schema.
  • Runtime validation - validate, parse, and transform query results at run-time, with broad or granular levels.

Brought to you by the team behind GroqD

groq-builder is the successor to GroqD. In addition to runtime validation and strongly-typed results, groq-builder adds schema-awareness and auto-completion.

Example

import { 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!

  • All the strings above are strongly-typed, based on field definitions, including 'products', 'price desc', 'slug.current', 'images[]', and 'url'.
  • In the projection, the keys name and price have auto-completion, and are strongly-typed, based on the fields of product.
  • In the projection, the keys slug and imageUrls are strongly-typed based on their sub-queries.

Example Query:

This example above generates the following GROQ query:

*[_type == "products"] | order(price desc)[0...10] {
  name,
  price,
  "slug": slug.current,
  "imageUrls": images[]->url
}

Example Types:

The example above also generates the following result 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>,
}>;

Runtime Validation

groq-builder enables effortless runtime validation using Zod:

import { z } from 'zod';

const products = q.star.filterByType('products').project(q => ({
  name: z.string(),
  slug: ["slug.current", z.string()],
  price: q.field("price", z.number().nonnegative()),
}));

Custom Parsing

Validation methods can include custom validation and/or parsing logic too:

const products = q.star.filterByType('products').project(q => ({
  price: z.number(),
  priceFormatted: q.field("price", price => formatCurrency(price)),
}));

Sanity Schema Configuration

To support auto-completion and maximum type-safety, you must configure groq-builder by providing type information for your Sanity Schema.

Fortunately, the Sanity CLI supports a typegen command that will generate the Sanity Schema Types for you!

Generating Sanity Schema Types

First, in your Sanity Studio project (where you have your sanity.config.ts), follow the Sanity documentation to run the following commands:

sanity schema extract --enforce-required-fields
sanity typegen generate

This generates a sanity.types.ts file, which contains type definitions for all your Sanity documents.

Second, copy the newly generated sanity.types.ts into your application (where you intend to use groq-builder).

Configuring groq-builder with your Sanity Schema:

In your application, you can create a strongly-typed groq-builder using the following snippet:

// ./q.ts
import { createGroqBuilder } from 'groq-builder';
import {
  AllSanitySchemaTypes,
  internalGroqTypeReferenceTo,
} from "./sanity.types.ts";

export const q = createGroqBuilder<{
  documentTypes: AllSanitySchemaTypes,
  referenceSymbol: typeof internalGroqTypeReferenceTo;
}>();

And that's it! Wherever you write queries, be sure to import this strongly-typed q and you'll get full auto-completion and type-safety!

import { q } from './q';

const productQuery = q.star.filterByType('product');

Package Sidebar

Install

npm i @danteissaias/groq-builder

Weekly Downloads

8

Version

0.9.2

License

MIT

Unpacked Size

126 kB

Total Files

117

Last publish

Collaborators

  • danteissaias