Skip to content

Commit

Permalink
Merge #1344
Browse files Browse the repository at this point in the history
1344: Add faceting index settings methods r=bidoubiwa a=Ugzuzg

# Pull Request

## Related issue
Fixes #1299

## PR checklist
Please check if your PR fulfills the following requirements:
- [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
- [x] Have you read the contributing guidelines?
- [x] Have you made sure that the title is accurate and descriptive of the changes?


Co-authored-by: Jarasłaŭ Viktorčyk <[email protected]>
  • Loading branch information
meili-bors[bot] and Ugzuzg authored Oct 4, 2022
2 parents 1481506 + 8ffa29d commit 3586193
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 3 deletions.
8 changes: 6 additions & 2 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,8 @@ getting_started_sorting: |-
sort: ['mass:asc'],
filter: 'mass < 200'
})
getting_started_faceting: |-
client.index('movies').updateFaceting({ maxValuesPerFacet: 2 })
getting_started_filtering: |-
client.index('meteorites').search('', { filter: 'mass < 200' })
get_filterable_attributes_1: |-
Expand Down Expand Up @@ -552,11 +554,13 @@ update_pagination_settings_1: |-
client.index('books').updateSettings({ pagination: { maxTotalHits: 100 }})
reset_pagination_settings_1: |-
get_faceting_settings_1: |-
client.index('books').getFaceting()
update_faceting_settings_1: |-
client.index('books').updateSettings({ faceting: { maxValuesPerFacet: 2 }})
client.index('books').updateFaceting({ maxValuesPerFacet: 2 })
reset_faceting_settings_1: |-
client.index('books').resetFaceting()
settings_guide_faceting_1: |-
client.index('books').updateSettings({ faceting: { maxValuesPerFacet: 5 }})
client.index('movies').updateSettings({ faceting: { maxValuesPerFacet: 5 }})
settings_guide_pagination_1: |-
client.index('books').updateSettings({ pagination: { maxTotalHits: 50 }})
search_parameter_guide_sort_1: |-
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,26 @@ client.index('myIndex').updateSortableAttributes(sortableAttributes: string[] |
client.index('myIndex').resetSortableAttributes(): Promise<EnqueuedTask>
```

### Faceting <!-- omit in toc -->

#### [Get faceting](https://docs.meilisearch.com/reference/api/settings.html#get-faceting-settings)

```ts
client.index('myIndex').getFaceting(): Promise<Faceting>
```

#### [Update faceting](https://docs.meilisearch.com/reference/api/settings.html#update-faceting-settings)

```ts
client.index('myIndex').updateFaceting(faceting: Faceting): Promise<EnqueuedTask>
```

#### [Reset faceting](https://docs.meilisearch.com/reference/api/settings.html#reset-faceting-settings)

```ts
client.index('myIndex').resetFaceting(): Promise<EnqueuedTask>
```

### Typo tolerance <!-- omit in toc -->

#### [Get typo tolerance](https://docs.meilisearch.com/reference/api/typo_tolerance.html#get-typo-tolerance)
Expand Down
43 changes: 43 additions & 0 deletions src/indexes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
DocumentsResults,
TasksQuery,
TasksResults,
Faceting,
} from './types'
import { removeUndefinedFromObject } from './utils'
import { HttpRequests } from './http-requests'
Expand Down Expand Up @@ -966,6 +967,48 @@ class Index<T = Record<string, any>> {

return task
}

///
/// FACETING
///

/**
* Get the faceting settings.
* @memberof Index
* @method getFaceting
* @returns {Promise<Faceting>} Promise containing object of faceting index settings
*/
async getFaceting(): Promise<Faceting> {
const url = `indexes/${this.uid}/settings/faceting`
return await this.httpRequest.get<Faceting>(url)
}

/**
* Update the faceting settings.
* @memberof Index
* @method updateFaceting
* @param {Faceting} faceting Faceting index settings object
* @returns {Promise<EnqueuedTask>} Promise containing object of the enqueued task
*/
async updateFaceting(faceting: Faceting): Promise<EnqueuedTask> {
const url = `indexes/${this.uid}/settings/faceting`
const task = await this.httpRequest.patch(url, faceting)

return new EnqueuedTask(task)
}

/**
* Reset the faceting settings.
* @memberof Index
* @method resetFaceting
* @returns {Promise<EnqueuedTask>} Promise containing object of the enqueued task
*/
async resetFaceting(): Promise<EnqueuedTask> {
const url = `indexes/${this.uid}/settings/faceting`
const task = await this.httpRequest.delete(url)

return new EnqueuedTask(task)
}
}

export { Index }
203 changes: 203 additions & 0 deletions tests/faceting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import { ErrorStatusCode } from '../src/types'
import {
clearAllIndexes,
config,
BAD_HOST,
MeiliSearch,
getClient,
dataset,
} from './utils/meilisearch-test-utils'

const index = {
uid: 'movies_test',
}

jest.setTimeout(100 * 1000)

afterAll(() => {
return clearAllIndexes(config)
})

describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
'Test on faceting',
({ permission }) => {
beforeEach(async () => {
await clearAllIndexes(config)
const client = await getClient('Master')
const { taskUid } = await client.createIndex(index.uid)
await client.waitForTask(taskUid)

const { taskUid: docTask } = await client
.index(index.uid)
.addDocuments(dataset)
await client.waitForTask(docTask)
})

test(`${permission} key: Get default faceting object`, async () => {
const client = await getClient(permission)

const response = await client.index(index.uid).getFaceting()

expect(response).toEqual({ maxValuesPerFacet: 100 })
})

test(`${permission} key: Update faceting settings`, async () => {
const client = await getClient(permission)
const newFaceting = { maxValuesPerFacet: 12 }
const task = await client.index(index.uid).updateFaceting(newFaceting)
await client.index(index.uid).waitForTask(task.taskUid)

const response = await client.index(index.uid).getFaceting()

expect(response).toEqual(newFaceting)
})

test(`${permission} key: Update faceting at null`, async () => {
const client = await getClient(permission)
const task = await client
.index(index.uid)
.updateFaceting({ maxValuesPerFacet: null })
await client.index(index.uid).waitForTask(task.taskUid)

const response = await client.index(index.uid).getFaceting()

expect(response).toEqual({ maxValuesPerFacet: 100 })
})

test(`${permission} key: Reset faceting`, async () => {
const client = await getClient(permission)
await client
.index(index.uid)
.waitForTask(
(
await client
.index(index.uid)
.updateFaceting({ maxValuesPerFacet: 12 })
).taskUid
)
const task = await client.index(index.uid).resetFaceting()
await client.index(index.uid).waitForTask(task.taskUid)

const response = await client.index(index.uid).getFaceting()

expect(response).toEqual({ maxValuesPerFacet: 100 })
})
}
)

describe.each([{ permission: 'Public' }])(
'Test on faceting',
({ permission }) => {
beforeEach(async () => {
const client = await getClient('Master')
const { taskUid } = await client.createIndex(index.uid)
await client.waitForTask(taskUid)
})

test(`${permission} key: try to get faceting and be denied`, async () => {
const client = await getClient(permission)
await expect(
client.index(index.uid).getFaceting()
).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY)
})

test(`${permission} key: try to update faceting and be denied`, async () => {
const client = await getClient(permission)
await expect(
client.index(index.uid).updateFaceting({ maxValuesPerFacet: 13 })
).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY)
})

test(`${permission} key: try to reset faceting and be denied`, async () => {
const client = await getClient(permission)
await expect(
client.index(index.uid).resetFaceting()
).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY)
})
}
)

describe.each([{ permission: 'No' }])('Test on faceting', ({ permission }) => {
beforeAll(async () => {
const client = await getClient('Master')
const { taskUid } = await client.createIndex(index.uid)
await client.waitForTask(taskUid)
})

test(`${permission} key: try to get faceting and be denied`, async () => {
const client = await getClient(permission)
await expect(client.index(index.uid).getFaceting()).rejects.toHaveProperty(
'code',
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
)
})

test(`${permission} key: try to update faceting and be denied`, async () => {
const client = await getClient(permission)
await expect(
client.index(index.uid).updateFaceting({ maxValuesPerFacet: 13 })
).rejects.toHaveProperty(
'code',
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
)
})

test(`${permission} key: try to reset faceting and be denied`, async () => {
const client = await getClient(permission)
await expect(
client.index(index.uid).resetFaceting()
).rejects.toHaveProperty(
'code',
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
)
})
})

describe.each([
{ host: BAD_HOST, trailing: false },
{ host: `${BAD_HOST}/api`, trailing: false },
{ host: `${BAD_HOST}/trailing/`, trailing: true },
])('Tests on url construction', ({ host, trailing }) => {
test(`Test getFaceting route`, async () => {
const route = `indexes/${index.uid}/settings/faceting`
const client = new MeiliSearch({ host })
const strippedHost = trailing ? host.slice(0, -1) : host
await expect(client.index(index.uid).getFaceting()).rejects.toHaveProperty(
'message',
`request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace(
'http://',
''
)}`
)
})

test(`Test updateFaceting route`, async () => {
const route = `indexes/${index.uid}/settings/faceting`
const client = new MeiliSearch({ host })
const strippedHost = trailing ? host.slice(0, -1) : host
await expect(
client.index(index.uid).updateFaceting({ maxValuesPerFacet: null })
).rejects.toHaveProperty(
'message',
`request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace(
'http://',
''
)}`
)
})

test(`Test resetFaceting route`, async () => {
const route = `indexes/${index.uid}/settings/faceting`
const client = new MeiliSearch({ host })
const strippedHost = trailing ? host.slice(0, -1) : host
await expect(
client.index(index.uid).resetFaceting()
).rejects.toHaveProperty(
'message',
`request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace(
'http://',
''
)}`
)
})
})
12 changes: 11 additions & 1 deletion tests/settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
expect(response).toHaveProperty('sortableAttributes', [])
expect(response).toHaveProperty('stopWords', [])
expect(response).toHaveProperty('synonyms', {})
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
})

test(`${permission} key: Get default settings of empty index with primary key`, async () => {
Expand All @@ -109,6 +110,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
expect(response).toHaveProperty('sortableAttributes', [])
expect(response).toHaveProperty('stopWords', [])
expect(response).toHaveProperty('synonyms', {})
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
})

test(`${permission} key: Update settings`, async () => {
Expand All @@ -135,7 +137,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
maxTotalHits: 1000,
},
faceting: {
maxValuesPerFacet: 100,
maxValuesPerFacet: 50,
},
}
// Add the settings
Expand Down Expand Up @@ -169,6 +171,9 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
disableOnWords: null,
disableOnAttributes: null,
},
faceting: {
maxValuesPerFacet: null,
},
}
// Add the settings
const task = await client.index(index.uid).updateSettings(newSettings)
Expand Down Expand Up @@ -204,6 +209,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
expect(response).toHaveProperty('displayedAttributes', ['*'])
expect(response).toHaveProperty('stopWords', newSettings.stopWords)
expect(response).toHaveProperty('synonyms', {})
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
})

test(`${permission} key: Reset settings`, async () => {
Expand All @@ -220,6 +226,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
expect(response).toHaveProperty('sortableAttributes', [])
expect(response).toHaveProperty('stopWords', [])
expect(response).toHaveProperty('synonyms', {})
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
})

test(`${permission} key: Reset settings of empty index`, async () => {
Expand All @@ -235,6 +242,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
expect(response).toHaveProperty('displayedAttributes', ['*'])
expect(response).toHaveProperty('stopWords', [])
expect(response).toHaveProperty('synonyms', {})
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
})

test(`${permission} key: Update searchableAttributes settings on empty index`, async () => {
Expand All @@ -259,6 +267,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
expect(response).toHaveProperty('displayedAttributes', expect.any(Array))
expect(response).toHaveProperty('stopWords', defaultSettings.stopWords)
expect(response).toHaveProperty('synonyms', {})
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
})

test(`${permission} key: Update searchableAttributes settings on empty index with a primary key`, async () => {
Expand Down Expand Up @@ -293,6 +302,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
expect(response).toHaveProperty('displayedAttributes', expect.any(Array))
expect(response).toHaveProperty('stopWords', defaultSettings.stopWords)
expect(response).toHaveProperty('synonyms', {})
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
})
}
)
Expand Down

0 comments on commit 3586193

Please sign in to comment.