FormidableLabs / groqd

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

Children required in contentBlocks #203

Closed rafaelderolez closed 11 months ago

rafaelderolez commented 1 year ago

Hey, I just started using groqd on a small side-project and have had a pretty good experience so far aside from this:

Error

Error: Error parsing:
`result.history.story[2].children`: Required

Are custom types in q.contentBlock(s) not supported?

Sanity

I have a object with a block in Sanity defined as such

export const history = {
  name: 'history',
  type: 'object',
  title: 'History',
  fields: [
    defineField({
      name: 'story',
      type: 'array',
      of: [
        { type: 'block' },
        { type: 'figure' },
      ],
    }),
  ],
}

GROQD

I query the content like this:

export const homePageQuery = q('*')
  .filter("_type == 'home' && language == $lang")
  .grab({
    history: q.object({
      story: q.contentBlocks(),
    }),
  })
  .slice(0)

Data

And here's the actual data from the same groq query (done via Vision):

{
    "story": [
        {
            "style": "h2",
            "_key": "1681cafcabad",
            "markDefs": [],
            "children": [
                {
                    "_type": "span",
                    "marks": [],
                    "text": "[redacted]",
                    "_key": "0d8483f03c770"
                }
            ],
            "_type": "block"
        },
        {
            "_key": "9308d4e3d265",
            "markDefs": [],
            "children": [
                {
                    "marks": [],
                    "text": "[redacted]",
                    "_key": "3edd606646ae",
                    "_type": "span"
                }
            ],
            "_type": "block",
            "style": "normal"
        },
        // 👇 This one is causing issues 👇
        {
            "_type": "figure",
            "alt": "[redacted]",
            "_key": "b5dfcc8c6f4d",
            "asset": {
                "_ref": "image-[redacted].jpg",
                "_type": "reference"
            }
        }
        // 👆 This one is causing issues 👆
    ]
}
maxyinger commented 1 year ago

Hey @rafaelderolez yea these are a little tricky. @fritz-c posted a nice solution to this same issue with a codesandbox example here

Applying that answer to what you have above, you'll basically want to make history a conditional selection that is q.contentBlock() when _type == "block" and is a figure selection when _type == "figure". You can read more about conditional selections here

Here's a groqd arcade example with your data and what you might use as the query. Your query will basically end up looking something like this:

export const homePageQuery = q('*')
  .filter("_type == 'home' && language == $lang")
  .grab({
    history: q("history").grab({
      story: q('story').filter().select({
        '_type == "block"': ["{...}", q.contentBlock()],
        '_type == "figure"': {
          _type: q.literal("figure"),
          asset: q('asset').grabOne('_ref', q.string())
          // whatever other fields you want to
          // grab on figure types
        },
        default: {
          _key: q.string(),
          _type: ['"unsupported"', q.literal("unsupported")],
          unsupportedType: ["_type", q.string()],
        },
      }),
    }),
  })
  .slice(0)
rafaelderolez commented 11 months ago

@littlemilkstudio thanks for that! I missed your comment and am currently on holiday, will get back to you in 2 weeks. Feel free to close this Issue, your explanation and examples look like they should do the trick 👍🏼

gksander commented 11 months ago

Closing this for now, but please re-open if you're still having troubles getting this working!

tutods commented 10 months ago

Hey @rafaelderolez yea these are a little tricky. @fritz-c posted a nice solution to this same issue with a codesandbox example here

Applying that answer to what you have above, you'll basically want to make history a conditional selection that is q.contentBlock() when _type == "block" and is a figure selection when _type == "figure". You can read more about conditional selections here

Here's a groqd arcade example with your data and what you might use as the query. Your query will basically end up looking something like this:

export const homePageQuery = q('*')
  .filter("_type == 'home' && language == $lang")
  .grab({
    history: q("history").grab({
      story: q('story').filter().select({
        '_type == "block"': ["{...}", q.contentBlock()],
        '_type == "figure"': {
          _type: q.literal("figure"),
          asset: q('asset').grabOne('_ref', q.string())
          // whatever other fields you want to
          // grab on figure types
        },
        default: {
          _key: q.string(),
          _type: ['"unsupported"', q.literal("unsupported")],
          unsupportedType: ["_type", q.string()],
        },
      }),
    }),
  })
  .slice(0)

Hi @littlemilkstudio I'm facing this error:

image

This is my content block query:

q('body')
    .filter()
    .select({
      '_type == "block"': ['{...}', q.contentBlock()],
      '_type == "gallery"': [
        `{..., "images": ${imagesListQuery('images').query}}`,
        galleryQuery.schema,
      ],
      '_type == "imageWithAlt"': nullToUndefined(imageWithAltQuery('').schema),
      '_type == "imageWithAltAndCaption"': nullToUndefined(imageWithAltAndCaptionQuery().schema),
      '_type == "quote"': ['{...}', quoteQuery],
      '_type == "relatedPosts"': [
        "{..., 'posts': posts[]->{title,'slug': slug.current, headline}}",
        relatedPostsQuery,
      ],
      '_type == "videoUrlWithCover"': videoUrlWithCoverQuery(''),
      default: {
        _key: q.string(),
        _type: ['"unsupported"', q.literal('unsupported')],
        unsupportedType: ['_type', q.string()],
      },
    })

The error appears after adding the nullToUndefined on both images queries, but if I remove the nullToUndefined on images, the PortableText shows me an error where the _key of the image is null and needs to be string | undefined. Do you have any idea how to fix this?