Skip to content

Commit 6cc7b43

Browse files
committed
feat: support search weight configuration for slug fields
1 parent fd8d0f3 commit 6cc7b43

File tree

3 files changed

+111
-6
lines changed

3 files changed

+111
-6
lines changed

packages/@sanity/types/src/schema/definition/type/slug.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import {type SlugifierFn, type SlugSourceFn} from '../../../slug'
33
import {type SlugIsUniqueValidator} from '../../../validation'
44
import {type RuleDef, type ValidationBuilder} from '../../ruleBuilder'
55
import {type InitialValueProperty} from '../../types'
6-
import {type BaseSchemaDefinition, type BaseSchemaTypeOptions} from './common'
6+
import {
7+
type BaseSchemaDefinition,
8+
type BaseSchemaTypeOptions,
9+
type SearchConfiguration,
10+
} from './common'
711

812
/** @public */
913
export interface SlugValue {
@@ -16,7 +20,7 @@ export interface SlugValue {
1620
export interface SlugRule extends RuleDef<SlugRule, SlugValue> {}
1721

1822
/** @public */
19-
export interface SlugOptions extends BaseSchemaTypeOptions {
23+
export interface SlugOptions extends SearchConfiguration, BaseSchemaTypeOptions {
2024
source?: string | Path | SlugSourceFn
2125
maxLength?: number
2226
slugify?: SlugifierFn

packages/sanity/src/core/search/common/__tests__/deriveSearchWeightsFromType.test.ts

+69
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,40 @@ describe('deriveSearchWeightsFromType', () => {
168168
})
169169
})
170170

171+
it('returns a weight of 0 for hidden slug fields', () => {
172+
const schema = createSchema({
173+
name: 'default',
174+
types: [
175+
defineType({
176+
name: 'testType',
177+
type: 'document',
178+
preview: {select: {}},
179+
fields: [
180+
defineField({
181+
name: 'someSlug',
182+
type: 'slug',
183+
hidden: true,
184+
}),
185+
],
186+
}),
187+
],
188+
})
189+
190+
expect(
191+
deriveSearchWeightsFromType({
192+
schemaType: schema.get('testType')!,
193+
maxDepth: 5,
194+
}),
195+
).toEqual({
196+
typeName: 'testType',
197+
paths: [
198+
{path: '_id', weight: 1},
199+
{path: '_type', weight: 1},
200+
{path: 'someSlug.current', weight: 0},
201+
],
202+
})
203+
})
204+
171205
it('respects `maxDepth`', () => {
172206
const schema = createSchema({
173207
name: 'default',
@@ -253,6 +287,21 @@ describe('deriveSearchWeightsFromType', () => {
253287
}),
254288
],
255289
}),
290+
defineType({
291+
name: 'testType2',
292+
type: 'document',
293+
preview: {
294+
select: {
295+
title: 'someSlug.current',
296+
},
297+
},
298+
fields: [
299+
defineField({
300+
name: 'someSlug',
301+
type: 'slug',
302+
}),
303+
],
304+
}),
256305
],
257306
})
258307

@@ -271,6 +320,20 @@ describe('deriveSearchWeightsFromType', () => {
271320
{path: 'descriptionField', weight: 1.5, mapWith: 'pt::text'},
272321
],
273322
})
323+
324+
expect(
325+
deriveSearchWeightsFromType({
326+
schemaType: schema.get('testType2')!,
327+
maxDepth: 5,
328+
}),
329+
).toEqual({
330+
typeName: 'testType2',
331+
paths: [
332+
{path: '_id', weight: 1},
333+
{path: '_type', weight: 1},
334+
{path: 'someSlug.current', weight: 10},
335+
],
336+
})
274337
})
275338

276339
it('returns special weights for fields that are selected in the preview config for cross dataset reference types', () => {
@@ -341,6 +404,11 @@ describe('deriveSearchWeightsFromType', () => {
341404
type: 'string',
342405
options: {search: {weight: 7}},
343406
}),
407+
defineField({
408+
name: 'someSlug',
409+
type: 'slug',
410+
options: {search: {weight: 7}},
411+
}),
344412
],
345413
}),
346414
],
@@ -361,6 +429,7 @@ describe('deriveSearchWeightsFromType', () => {
361429
{path: 'subtitleField', weight: 7},
362430
{path: 'descriptionField', weight: 7},
363431
{path: 'normalStringField', weight: 7},
432+
{path: 'someSlug.current', weight: 7},
364433
],
365434
})
366435
})

packages/sanity/src/core/search/common/deriveSearchWeightsFromType.ts

+36-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import {type CrossDatasetType, type SchemaType, type SearchConfiguration} from '@sanity/types'
1+
import {
2+
type CrossDatasetType,
3+
type SchemaType,
4+
type SearchConfiguration,
5+
type SlugSchemaType,
6+
} from '@sanity/types'
27
import {toString as pathToString} from '@sanity/util/paths'
38

49
import {isRecord} from '../../util'
@@ -20,7 +25,7 @@ const BASE_WEIGHTS: Record<string, Omit<SearchWeightEntry, 'path'>> = {
2025
_id: {weight: 1, type: 'string'},
2126
_type: {weight: 1, type: 'string'},
2227
}
23-
const ignoredBuiltInObjectTypes = ['reference', 'crossDatasetReference']
28+
const ignoredBuiltInObjectTypes = ['reference', 'crossDatasetReference', 'slug']
2429

2530
const getTypeChain = (type: SchemaType | undefined): SchemaType[] =>
2631
type ? [type, ...getTypeChain(type.type)] : []
@@ -32,13 +37,27 @@ const isPtField = (type: SchemaType | undefined) =>
3237
const isStringField = (schemaType: SchemaType | undefined): boolean =>
3338
schemaType ? schemaType?.jsonType === 'string' : false
3439

40+
const isSlugField = (schemaType: SchemaType | undefined): schemaType is SlugSchemaType => {
41+
const typeChain = getTypeChain(schemaType)
42+
return typeChain.some(({jsonType, name}) => jsonType === 'object' && name === 'slug')
43+
}
44+
3545
const isSearchConfiguration = (options: unknown): options is SearchConfiguration =>
3646
isRecord(options) && 'search' in options && isRecord(options.search)
3747

3848
function isSchemaType(input: SchemaType | CrossDatasetType | undefined): input is SchemaType {
3949
return typeof input !== 'undefined' && 'name' in input
4050
}
4151

52+
function getFullyQualifiedPath(schemaType: SchemaType, path: string): string {
53+
// Slug field weights should be applied to the object's `current` field.
54+
if (isSlugField(schemaType)) {
55+
return [path, 'current'].join('.')
56+
}
57+
58+
return path
59+
}
60+
4261
function getLeafWeights(
4362
schemaType: SchemaType | CrossDatasetType | undefined,
4463
maxDepth: number,
@@ -61,7 +80,20 @@ function getLeafWeights(
6180
return [{path, weight, type: isPtField(type) ? 'pt' : 'string'}]
6281
}
6382

83+
if (isSlugField(type)) {
84+
const weight = getWeight(type, path)
85+
if (typeof weight !== 'number') return []
86+
return [
87+
{
88+
path: getFullyQualifiedPath(type, path),
89+
weight,
90+
type: isPtField(type) ? 'pt' : 'string',
91+
},
92+
]
93+
}
94+
6495
const results: SearchWeightEntry[] = []
96+
6597
const objectTypes = typeChain.filter(
6698
(t): t is Extract<SchemaType, {jsonType: 'object'}> =>
6799
t.jsonType === 'object' &&
@@ -173,8 +205,8 @@ const getPreviewWeights = (
173205
)
174206
}
175207

176-
return getLeafWeights(schemaType, maxDepth, (_, path) => {
177-
const nested = nestedWeightsBySelectionPath[path]
208+
return getLeafWeights(schemaType, maxDepth, (type, path) => {
209+
const nested = nestedWeightsBySelectionPath[getFullyQualifiedPath(type, path)]
178210
return nested ? nested.weight : null
179211
})
180212
}

0 commit comments

Comments
 (0)