Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/autocomplete-client/__tests__/test.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const MOVIES = [
genres: ['Drama', 'Crime', 'Comedy'],
poster: 'https://image.tmdb.org/t/p/w500/ojDg0PGvs6R9xYFodRct2kdI6wC.jpg',
release_date: 593395200,
reviews: [
{ id: 1, author: 'John', content: 'one star' },
{ id: 2, author: 'Jane', content: 'two stars' },
],
},
{
id: 5,
Expand All @@ -35,6 +39,10 @@ export const MOVIES = [
genres: ['Crime', 'Comedy'],
poster: 'https://image.tmdb.org/t/p/w500/75aHn1NOYXh4M7L5shoeQ6NGykP.jpg',
release_date: 818467200,
reviews: [
{ id: 3, author: 'John', content: 'three stars' },
{ id: 4, author: 'Jane', content: 'four stars' },
],
},
{
id: 6,
Expand All @@ -44,6 +52,10 @@ export const MOVIES = [
genres: ['Action', 'Thriller', 'Crime'],
poster: 'https://image.tmdb.org/t/p/w500/rYFAvSPlQUCebayLcxyK79yvtvV.jpg',
release_date: 750643200,
reviews: [
{ id: 5, author: 'John', content: 'five stars' },
{ id: 6, author: 'Jane', content: 'six stars' },
],
},
{
id: 11,
Expand All @@ -53,6 +65,10 @@ export const MOVIES = [
genres: ['Adventure', 'Action', 'Science Fiction'],
poster: 'https://image.tmdb.org/t/p/w500/6FfCtAuVAW8XJjZ7eWeLibRLWTw.jpg',
release_date: 233366400,
reviews: [
{ id: 7, author: 'John', content: 'seven stars' },
{ id: 8, author: 'Jane', content: 'eight stars' },
],
},
{
id: 30,
Expand All @@ -61,6 +77,10 @@ export const MOVIES = [
genres: ['Animation', 'Science Fiction'],
poster: 'https://image.tmdb.org/t/p/w500/gSuHDeWemA1menrwfMRChnSmMVN.jpg',
release_date: 819676800,
reviews: [
{ id: 9, author: 'John', content: 'nine stars' },
{ id: 10, author: 'Jane', content: 'ten stars' },
],
},
{
id: 24,
Expand All @@ -69,6 +89,10 @@ export const MOVIES = [
genres: ['Action', 'Crime'],
poster: 'https://image.tmdb.org/t/p/w500/v7TaX8kXMXs5yFFGR41guUDNcnB.jpg',
release_date: 1065744000,
reviews: [
{ id: 11, author: 'John', content: 'eleven stars' },
{ id: 12, author: 'Jane', content: 'twelve stars' },
],
},
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,18 @@ describe('fetchMeilisearchResults', () => {
matchedWords: [],
})
})

test('highlight results skips attributes missing value key', async () => {
const results = await fetchMeilisearchResults({
searchClient,
queries: [
{
indexName: INDEX_NAME,
query: 'kill bill',
},
],
})

expect(results[0].hits[0]._highlightResult?.reviews).toEqual(undefined)
})
})
46 changes: 37 additions & 9 deletions packages/autocomplete-client/src/search/fetchMeilisearchResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,27 @@ export function fetchMeilisearchResults<TRecord = Record<string, any>>({
...hit,
_highlightResult: (
Object.entries(hit?._highlightResult || {}) as Array<
| [keyof TRecord, { value: string }]
| [keyof TRecord, Array<{ value: string }>] // if the field is an array
[keyof TRecord, PossibleHighlightResult]
>
).reduce((acc, [field, highlightResult]) => {
return {
...acc,
// if the field is an array, highlightResult is an array of objects
[field]: mapOneOrMany(highlightResult, (highlightResult) =>
calculateHighlightMetadata(
if (!isDefinedHighlightValue(highlightResult)) {
return acc
}

// if the field is an array, highlightResult is an array of objects
acc[field] = mapOneOrMany(
highlightResult,
(highlightResult) => {
return calculateHighlightMetadata(
query.query || '',
query.params?.highlightPreTag || HIGHLIGHT_PRE_TAG,
query.params?.highlightPostTag || HIGHLIGHT_POST_TAG,
highlightResult.value
)
),
}
}
)

return acc
}, {} as HighlightResult<TRecord>),
})),
}
Expand Down Expand Up @@ -144,3 +149,26 @@ function calculateHighlightMetadata(
function mapOneOrMany<T, U>(value: T | T[], mapFn: (value: T) => U): U | U[] {
return Array.isArray(value) ? value.map(mapFn) : mapFn(value)
}

type DefinedHighlightResult = { value: string } | Array<{ value: string }> // if the field is an array

/**
* Some fields may not return a value at all - nested arrays/objects for example
*
* Ideally server honours the `attributesToHighlight` param and only includes
* those attributes in the response rather than all attributes (highlighted or
* not)
*/
type UndefinedHighlightResult = { value?: never } | Array<{ value?: never }>

type PossibleHighlightResult = DefinedHighlightResult | UndefinedHighlightResult

function isDefinedHighlightValue(
input: PossibleHighlightResult
): input is DefinedHighlightResult {
if (Array.isArray(input)) {
return input.every((r) => typeof r.value === 'string')
}

return typeof input.value === 'string'
}