sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
311 lines (278 loc) • 8.8 kB
text/typescript
import {Schema} from '@sanity/schema'
import {defineArrayMember, defineField, defineType} from '@sanity/types'
import {describe, expect, it} from 'vitest'
import {DEFAULT_LIMIT} from '../weighted/createSearchQuery'
import {createSearchQuery} from './createSearchQuery'
const testType = Schema.compile({
types: [
defineType({
name: 'basic-schema-test',
type: 'document',
preview: {
select: {
title: 'title',
},
},
fields: [
defineField({
name: 'title',
type: 'string',
options: {
search: {
weight: 10,
},
},
}),
],
}),
],
}).get('basic-schema-test')
describe('createSearchQuery', () => {
describe('searchTerms', () => {
it('should create query for basic type', () => {
const {query, params} = createSearchQuery(
{
query: 'test',
types: [testType],
},
'',
)
expect(query).toMatchInlineSnapshot(
`
"// findability-mvi:5
*[_type in $__types] | score(boost(_type in ["basic-schema-test"] && title match text::query($__query), 10), [@, _id] match text::query($__query)) | order(_score desc) [_score > 0] [0...$__limit] {_score, _type, _id, _originalId}"
`,
)
expect(params).toEqual({
__query: '*',
__types: ['basic-schema-test'],
__limit: DEFAULT_LIMIT + 1,
})
})
})
describe('searchOptions', () => {
it('should include drafts by default', () => {
const {query, options} = createSearchQuery(
{
query: 'term0',
types: [testType],
},
'',
)
expect(query).not.toMatch(`!(_id in path('drafts.**'))`)
expect(options.perspective).toBe('raw')
})
it('should exclude drafts when configured', () => {
const {query, options} = createSearchQuery(
{
query: 'term0',
types: [testType],
},
'',
{includeDrafts: false},
)
expect(query).toMatch(`!(_id in path('drafts.**'))`)
expect(options.perspective).toBe('raw')
})
it('should use `raw` perspective when no perspective provided', () => {
const {options} = createSearchQuery(
{
query: 'term0',
types: [testType],
},
'',
)
expect(options.perspective).toBe('raw')
})
it('should use `raw` perspective when empty perspective array provided', () => {
const {options} = createSearchQuery(
{
query: 'term0',
types: [testType],
},
'',
{perspective: []},
)
expect(options.perspective).toBe('raw')
})
it('should use provided limit (plus one to determine existence of next page)', () => {
const {params} = createSearchQuery(
{
query: 'term0',
types: [testType],
},
'',
{
limit: 30,
},
)
expect(params.__limit).toEqual(31)
})
it('should add configured filter and params', () => {
const {query, params} = createSearchQuery(
{
query: 'term',
types: [testType],
},
'',
{filter: 'randomCondition == $customParam', params: {customParam: 'custom'}},
)
expect(query).toContain('*[_type in $__types && (randomCondition == $customParam)]')
expect(params.customParam).toEqual('custom')
})
it('should use configured tag', () => {
const {options} = createSearchQuery(
{
query: 'term',
types: [testType],
},
'',
{tag: 'customTag'},
)
expect(options.tag).toEqual('customTag')
})
it('should use configured sort field and direction', () => {
const {query} = createSearchQuery(
{
query: 'test',
types: [testType],
},
'',
{
sort: [
{
direction: 'desc',
field: 'exampleField',
},
],
},
)
expect(query).toMatchInlineSnapshot(`
"// findability-mvi:5
*[_type in $__types && [@, _id] match text::query($__query)] | order(exampleField desc) [0...$__limit] {exampleField, _type, _id, _originalId}"
`)
expect(query).toContain('| order(exampleField desc)')
})
it('should use multiple sort fields and directions', () => {
const {query} = createSearchQuery(
{
query: 'test',
types: [testType],
},
'',
{
sort: [
{
direction: 'desc',
field: 'exampleField',
},
{
direction: 'asc',
field: 'anotherExampleField',
},
{
direction: 'asc',
field: 'mapWithField',
mapWith: 'lower',
},
],
},
)
expect(query).toMatchInlineSnapshot(`
"// findability-mvi:5
*[_type in $__types && [@, _id] match text::query($__query)] | order(exampleField desc,anotherExampleField asc,lower(mapWithField) asc) [0...$__limit] {exampleField, anotherExampleField, mapWithField, _type, _id, _originalId}"
`)
expect(query).toContain(
'| order(exampleField desc,anotherExampleField asc,lower(mapWithField) asc)',
)
})
it('should order results by _score desc if no sort field and direction is configured', () => {
const {query} = createSearchQuery(
{
query: 'test',
types: [testType],
},
'',
)
expect(query).toMatchInlineSnapshot(`
"// findability-mvi:5
*[_type in $__types] | score(boost(_type in ["basic-schema-test"] && title match text::query($__query), 10), [@, _id] match text::query($__query)) | order(_score desc) [_score > 0] [0...$__limit] {_score, _type, _id, _originalId}"
`)
expect(query).toContain('| order(_score desc)')
})
it('should prepend comments (with new lines) if comments is configured', () => {
const {query} = createSearchQuery(
{
query: 'test',
types: [testType],
},
'',
{
comments: ['foo=1', 'bar'],
},
)
const lines = query.split('\n')
expect(lines[0]).toEqual(`// findability-mvi:5`)
expect(lines[1]).toEqual('// foo=1')
expect(lines[2]).toEqual('// bar')
})
})
describe('search config', () => {
it('should handle indexed array fields in an optimized manner', () => {
const {query} = createSearchQuery(
{
query: 'term0 term1',
types: [
Schema.compile({
types: [
defineType({
name: 'numbers-in-path',
type: 'document',
fields: [
defineField({
name: 'cover',
type: 'array',
of: [
defineArrayMember({
type: 'object',
fields: [
defineField({
name: 'cards',
type: 'array',
of: [
defineArrayMember({
type: 'object',
fields: [
defineField({
name: 'title',
type: 'string',
options: {
search: {
weight: 5,
},
},
}),
],
}),
],
}),
],
}),
],
}),
],
}),
],
}).get('numbers-in-path'),
],
},
'',
)
expect(query).toMatchInlineSnapshot(`
"// findability-mvi:5
*[_type in $__types] | score(boost(_type in ["numbers-in-path"] && cover[].cards[].title match text::query($__query), 5), [@, _id] match text::query($__query)) | order(_score desc) [_score > 0] [0...$__limit] {_score, _type, _id, _originalId}"
`)
expect(query).toContain('cover[].cards[].title match text::query($__query), 5)')
})
})
})