Skip to content

Instantly share code, notes, and snippets.

@devinhalladay
Last active March 4, 2022 23:03
Show Gist options
  • Save devinhalladay/72704afb4fcfaade478b4f8977637925 to your computer and use it in GitHub Desktop.
Save devinhalladay/72704afb4fcfaade478b4f8977637925 to your computer and use it in GitHub Desktop.
Valiating slugs of child documents in parent→child relations for Sanity Studio
import ComputedField from 'sanity-plugin-computed-field';
import { validateLessonSlugUniqueness } from '../../utils/validateLessonSlugUniquness';
import { getPublishedId } from '../../utils/documentPublishStatus';
export default {
name: 'lesson',
title: 'Lesson',
type: 'document',
fields: [
/**
* This field uses the computed field plugin to compute the most recently
* published course that this lesson belongs to.
* Right now, course-lesson relationships are one-to-one.
*/
{
title: 'Parent Course',
name: 'referringCourse',
description:
'The course this lesson belongs to. A lesson can be associated with one course at a time.',
type: 'reference',
to: [{ type: 'course' }],
weak: true,
inputComponent: ComputedField,
options: {
buttonText: 'Re-link lesson',
documentQuerySelection: `// groq
"course": *[_type == "course" && references(^._id)][0]`,
reduceQueryResult: (queryResult) => {
if (queryResult.course) {
/**
* Set a reference to the implied parent course.
*/
return {
_type: 'reference',
_ref: getPublishedId(queryResult.course._id),
};
}
return null;
},
},
},
/**
* Here we will use our custom uniquness function to ensure that the slug
* is unique within the course.
*/
{
name: 'slug',
type: 'slug',
options: { source: 'title', isUnique: validateLessonSlugUniqueness },
},
/**
* If you are using the generalized version of the function validateNestedSlugUniqueness,
* you can use the following to validate uniqueness.
{
name: 'slug',
type: 'slug',
options: {
source: 'title',
isUnique: async (value, context) => {
const isUnique = await validateNestedSlugUniqueness(
value,
context,
'referringCourse',
);
return isUnique;
},
},
},
*/
],
};
/**
* This file is specific to my schema, and validates the uniqueness of slugs for lessons with the same "parent" course.
* In our schema, the parent course is accessed via a calculated `referringCourse` field, but this could also be
* done by using the `references()` function in groq.
*/
import { getPublishedId } from './documentPublishStatus';
import { SanityDocument } from '@sanity/client';
import client from '../sanityClient';
interface ValidationContext {
/**
* The field's parent object. This might be the document.
*/
parent: Record<string, any>;
/**
* The parent document
*/
document: SanityDocument;
}
/**
* Validates that the slug is unique within the current course.
*
* @param value The slug to validate.
* @param context The context of the slug field.
* @returns A promise that resolves to true if the slug is unique, false otherwise.
*/
export const validateLessonSlugUniqueness = async (
value: string | null | undefined,
context: ValidationContext,
): Promise<boolean> => {
const slug = value;
const currentParentCourse = context.document?.referringCourse;
/** If there is no parent course, check against all lesson documents. */
if (!currentParentCourse) {
return client.fetch(
`*[(_type == "lesson") && !(_id in path("drafts.**"))]`,
);
}
/** Fetch all other lessons with the same slug, within the same course. */
const lessonsWithSameSlug = await client.fetch(
`*[
(_type == "lesson")
&& !(_id in path('drafts.**'))
&& _id != $currentId
&& slug.current == $slug
&& referringCourse._ref == $parentCourseId
]._id
`,
{
slug,
currentId: getPublishedId(context.document._id),
parentCourseId: currentParentCourse._ref,
},
);
return !lessonsWithSameSlug.length;
};
/**
* This file is more generalized for any schema. It still relies on a field on the child document which
* references the parent — in my case this is calculated with sanity-plugin-computed-field.
* However, if this does not fit your needs, you can simply get the parent course using the `references()` function in groq.
*/
interface ValidationContext {
/**
* The field's parent object. This might be the document.
*/
parent: Record<string, any>;
/**
* The parent document
*/
document: SanityDocument;
}
/**
* Validates that the slug is unique within a parent document, such as lessons belonging to a course.
*
* @param value The slug to validate.
* @param context The context of the slug field.
* @returns A promise that resolves to true if the slug is unique, false otherwise.
*/
export const validateNestedSlugUniqueness = async (
value: string | null | undefined,
context: ValidationContext,
parentReferenceField: string,
): Promise<boolean> => {
const slug = value;
const currentParentDocument = context.document[parentReferenceField];
/** If there is no parent document referenced, check against all documents of the current type. */
if (!currentParentDocument) {
const allDocumentsWithSameSlug = client.fetch(
`*[(_type == $childType) && !(_id in path("drafts.**"))]`,
{
childType: context.document._type,
},
);
return !allDocumentsWithSameSlug.length;
}
/** Fetch all other documents of the current type with the same slug, with the same parent document reference. */
const childDocumentsWithSameSlug = await client.fetch(
`*[
(_type == $childType)
&& !(_id in path('drafts.**'))
&& _id != $currentChildId
&& slug.current == $slug
&& @[parentReferenceField]->._id == $parentDocumentId
]._id
`,
{
slug,
currentChildId: getPublishedId(context.document._id),
parentDocumentId: currentParentDocument._ref,
childType: context.document._type,
parentReferenceField: 'referringCourse',
},
);
return !childDocumentsWithSameSlug.length;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment