FormidableLabs / groqd

A schema-unaware, runtime and type-safe query builder for GROQ.
https://commerce.nearform.com/open-source/groqd
MIT License
221 stars 17 forks source link

groq-builder projections on field #269

Open heggemsnes opened 4 months ago

heggemsnes commented 4 months ago

Is there an existing issue for this?

Code of Conduct

Question

Hi

I have a question regarding a common pattern we have for reusing queries, check out my example repo here: https://github.com/heggemsnes/groq-builder-example

I am wondering how to create a reusable "pageBuilder" pattern. I have tried to add some examples in the repo. 

Basically I want to define a fragment like this:

const sectionsFragment = q
  .fragment<SanityValues["sections"]>()
  .project((q) => ({
    ...q.conditionalByType({
      articleSection: {
        title: true,
        // Using page here for simplicity, but this would be a reference to a article.
        // @ts-expect-error Causes same error.
        articles: q.star.filterByType("page").slice(0, 3).project({
          title: true,
          slug: "slug.current",
        }),
      },
      imageSection: {
        image: true,
      },
    }),
  }));

And use it on a projection kinda like this:

const pageWithSectionsQuery = q.star
  .filterByType("pageWithSections")
  .slice(0)
  .project({
    title: true,
    sections: q.field("sections[]").project(sectionsFragment),
  });

Would love some pointers on how this pattern might be possible as it is quite common for us i.e. for nested blocks in portable text as well.

PS: Sorry for spamming, but just got excited by this package!
heggemsnes commented 4 months ago

I am managing to work around this currently by doing this which is not really that good looking :)

import { SectionsType, sectionsFragment } from "./../../lib/queries/sections.query";
import { q } from "@/lib/queries/groq-builder";
import { FragmentInputTypeTag, InferResultType } from "groq-builder";

// @ts-expect-error
export const pageQuery = q.star
  .filterByType("page")
  .filter("slug.current == $slug")
  .slice(0)
  .project({
    title: true,
    sections: q.raw<SectionsType[]>(`sections[]{
      ${sectionsFragment["[CONDITIONAL] [BY_TYPE]"].query}
    }`),
  });

export type PageQuery = InferResultType<typeof pageQuery>;
scottrippey commented 2 months ago

The sample you posted does look correct! You've created a fragment with a conditional projection. This should be supported, here's the unit tests: https://github.com/FormidableLabs/groqd/blob/main/packages/groq-builder/src/commands/fragment.test.ts#L141-L198

Can you give me a little more detail on the errors you're experiencing?