diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 9151c0c7..487089ae 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -3,6 +3,12 @@ # the documentation on build # You can read more on https://github.com/meilisearch/documentation/tree/master/.vuepress/code-samples --- +facet_search_2: |- + await client.index('books').updateFaceting(Faceting(sortFacetValuesBy: {'genres': 'count'})); +getting_started_faceting: |- + await client.index('books').updateFaceting(Faceting(maxValuesPerFacet: 2, sortFacetValuesBy: {'*': 'count'})); +update_faceting_settings_1: |- + await client.index('books').updateFaceting(Faceting(maxValuesPerFacet: 2, sortFacetValuesBy: {'*': 'alpha', 'genres': 'count'})); search_parameter_guide_attributes_to_search_on_1: |- await client.index('movies').search('adventure', SearchQuery(attributesToSearchOn: ['overview'])); get_documents_post_1: |- @@ -88,7 +94,6 @@ search_parameter_guide_hitsperpage_1: |- await client.index('movies').search('', SearchQuery(hitsPerPage: 15)) as PaginatedSearchResult; search_parameter_guide_page_1: |- await client.index('movies').search('', SearchQuery(page: 2)) as PaginatedSearchResult; -getting_started_faceting: |- getting_started_pagination: |- synonyms_guide_1: |- await client.index('movies').updateSynonyms({ @@ -122,7 +127,7 @@ get_pagination_settings_1: |- update_pagination_settings_1: |- reset_pagination_settings_1: |- get_faceting_settings_1: |- -update_faceting_settings_1: |- + reset_faceting_settings_1: |- get_one_index_1: |- await client.getIndex('movies'); diff --git a/lib/src/settings/faceting.dart b/lib/src/settings/faceting.dart index d17678b0..d3955329 100644 --- a/lib/src/settings/faceting.dart +++ b/lib/src/settings/faceting.dart @@ -1,25 +1,57 @@ -const _defaultmaxValuesPerFacet = 100; +import 'package:meilisearch/src/annotations.dart'; + +enum FacetingSortTypes { + alpha('alpha'), + count('count'); + + final String value; + + const FacetingSortTypes(this.value); +} class Faceting { - //Define maximum number of value returned for a facet for a **search query**. - //It means that with the default value of `100`, - //it is not possible to have `101` different colors if the `color`` field is defined as a facet at search time. - int maxValuesPerFacet; + /// Define maximum number of value returned for a facet for a **search query**. + /// It means that with the default value of `100`, + /// it is not possible to have `101` different colors if the `color`` field is defined as a facet at search time. + final int? maxValuesPerFacet; + + /// Defines how facet values are sorted. + /// + /// By default, all facets (`*`) are sorted by name, alphanumerically in ascending order (`alpha`). + /// + /// `count` sorts facet values by the number of documents containing a facet value in descending order. + /// + /// example: + /// "*": 'alpha + /// "genres": count + @RequiredMeiliServerVersion('1.3.0') + final Map? sortFacetValuesBy; - Faceting({ - this.maxValuesPerFacet = _defaultmaxValuesPerFacet, + const Faceting({ + this.maxValuesPerFacet, + this.sortFacetValuesBy, }); Map toMap() { return { - 'maxValuesPerFacet': maxValuesPerFacet, + if (maxValuesPerFacet != null) 'maxValuesPerFacet': maxValuesPerFacet, + if (sortFacetValuesBy != null) + 'sortFacetValuesBy': + sortFacetValuesBy?.map((key, value) => MapEntry(key, value.value)), }; } factory Faceting.fromMap(Map map) { return Faceting( - maxValuesPerFacet: - map['maxValuesPerFacet'] as int? ?? _defaultmaxValuesPerFacet, + maxValuesPerFacet: map['maxValuesPerFacet'] as int?, + sortFacetValuesBy: + (map['sortFacetValuesBy'] as Map?)?.map( + (key, value) => MapEntry( + key, + FacetingSortTypes.values + .firstWhere((element) => element.value == value), + ), + ), ); } } diff --git a/test/settings_test.dart b/test/settings_test.dart index 0406bb77..0c457e49 100644 --- a/test/settings_test.dart +++ b/test/settings_test.dart @@ -45,6 +45,10 @@ void main() { ), faceting: Faceting( maxValuesPerFacet: 200, + sortFacetValuesBy: { + '*': FacetingSortTypes.count, + 'genres': FacetingSortTypes.alpha, + }, ), ), ) @@ -67,6 +71,15 @@ void main() { expect(settings.typoTolerance?.disableOnWords, contains('prince')); expect(settings.typoTolerance?.minWordSizeForTypos?.oneTypo, equals(3)); expect(settings.faceting?.maxValuesPerFacet, equals(200)); + expect( + settings.faceting?.sortFacetValuesBy, + allOf( + isNotNull, + isNotEmpty, + containsPair('*', FacetingSortTypes.count), + containsPair('genres', FacetingSortTypes.alpha), + ), + ); }); test('Reseting the settings', () async { @@ -314,9 +327,20 @@ void main() { }); group('Faceting', () { + const defaultFaceting = Faceting( + maxValuesPerFacet: 100, + sortFacetValuesBy: { + '*': FacetingSortTypes.alpha, + }, + ); + Future doUpdate() async { final toUpdate = Faceting( maxValuesPerFacet: 200, + sortFacetValuesBy: { + '*': FacetingSortTypes.count, + 'genres': FacetingSortTypes.alpha, + }, ); var response = await index.updateFaceting(toUpdate).waitFor(client: client); @@ -332,7 +356,11 @@ void main() { expect( initial.toMap(), - equals(initialFromSettings?.toMap()), + initialFromSettings?.toMap(), + ); + expect( + initial.toMap(), + defaultFaceting.toMap(), ); }); @@ -363,11 +391,11 @@ void main() { await index.getSettings().then((value) => value.faceting); expect( afterReset.toMap(), - equals(Faceting().toMap()), + equals(defaultFaceting.toMap()), ); expect( afterResetFromSettings?.toMap(), - equals(Faceting().toMap()), + equals(defaultFaceting.toMap()), ); }); });