diff --git a/packages/client/src/builders/search/index.ts b/packages/client/src/builders/search/index.ts index 45aecb3..cb68f74 100644 --- a/packages/client/src/builders/search/index.ts +++ b/packages/client/src/builders/search/index.ts @@ -13,4 +13,5 @@ export * from './searchTermPredictionBuilder'; export * from './dataObjectValueSelectorBuilder'; export * from './getProductFacet'; export * from './getContentFacet'; -export * from './getProductCategoryFacet'; \ No newline at end of file +export * from './getProductCategoryFacet'; +export * from './searchConstraintBuilder'; \ No newline at end of file diff --git a/packages/client/src/builders/search/productSearchBuilder.ts b/packages/client/src/builders/search/productSearchBuilder.ts index 4fae64b..b934b50 100644 --- a/packages/client/src/builders/search/productSearchBuilder.ts +++ b/packages/client/src/builders/search/productSearchBuilder.ts @@ -1,9 +1,10 @@ -import { ProductSearchRequest, ProductSearchSettings, RecommendationSettings, RetailMediaQuery, SelectedBrandPropertiesSettings, SelectedProductPropertiesSettings, SelectedVariantPropertiesSettings, VariantSearchSettings } from '../../models/data-contracts'; +import { ProductSearchRequest, ProductSearchSettings, RecommendationSettings, ResultMustHaveVariantConstraint, RetailMediaQuery, SelectedBrandPropertiesSettings, SelectedProductPropertiesSettings, SelectedVariantPropertiesSettings, VariantSearchSettings } from '../../models/data-contracts'; import { PaginationBuilder } from '../paginationBuilder'; import { Settings } from '../settings'; import { FacetBuilder } from './facetBuilder'; import { ProductSortingBuilder } from './productSortingBuilder'; import { SearchBuilder } from './searchBuilder'; +import { SearchConstraintBuilder } from './searchConstraintBuilder'; import { SearchRequestBuilder } from './searchRequestBuilder'; export class ProductSearchBuilder extends SearchRequestBuilder implements SearchBuilder { @@ -11,6 +12,7 @@ export class ProductSearchBuilder extends SearchRequestBuilder implements Search private retailMediaQuery: RetailMediaQuery | null = null; private paginationBuilder: PaginationBuilder = new PaginationBuilder(); private sortingBuilder: ProductSortingBuilder = new ProductSortingBuilder(); + private searchConstraintBuilder: SearchConstraintBuilder = new SearchConstraintBuilder(); private term: string | null | undefined; private searchSettings: ProductSearchSettings = { @@ -104,6 +106,14 @@ export class ProductSearchBuilder extends SearchRequestBuilder implements Search return this; } + public searchConstraints(searchConstraintbuilder: (searchConstraintBuilder: SearchConstraintBuilder) => void): this { + searchConstraintbuilder(this.searchConstraintBuilder); + + this.searchSettings.resultConstraint = this.searchConstraintBuilder.build(); + + return this; + } + public build(): ProductSearchRequest { const { take, skip } = this.paginationBuilder.build(); return { diff --git a/packages/client/src/builders/search/searchConstraintBuilder.ts b/packages/client/src/builders/search/searchConstraintBuilder.ts new file mode 100644 index 0000000..fb1944d --- /dev/null +++ b/packages/client/src/builders/search/searchConstraintBuilder.ts @@ -0,0 +1,21 @@ +import { ProductSearchResultConstraint, ResultMustHaveVariantConstraint } from '../../models/data-contracts'; + +export class SearchConstraintBuilder { + private resultConstraint: ProductSearchResultConstraint | null = null; + + public setResultMustHaveVariantConstraint(constaint: { exceptWhenProductHasNoVariants: boolean }): this { + const constraint: ResultMustHaveVariantConstraint = { + $type: 'Relewise.Client.Requests.Search.Settings.ResultMustHaveVariantConstraint, Relewise.Client', + ...constaint, + }; + + this.resultConstraint = constraint; + return this; + } + + build(): ResultMustHaveVariantConstraint | null { + // Do to how the data contracts are generated, resultsConstraints on searchSettings expect this specific type + // Once more types are added it will expect the generic type and this cast should be removed and the generic type should be returned + return this.resultConstraint as ResultMustHaveVariantConstraint | null; + } +} diff --git a/packages/client/tests/integration-tests/productSearch.integration.test.ts b/packages/client/tests/integration-tests/productSearch.integration.test.ts index ecf4efc..74c0f81 100644 --- a/packages/client/tests/integration-tests/productSearch.integration.test.ts +++ b/packages/client/tests/integration-tests/productSearch.integration.test.ts @@ -82,4 +82,15 @@ test('Facet result', async() => { } expect(result?.hits).toBeGreaterThan(0); -}); \ No newline at end of file +}); + +test('ProductSearch with search constraint', async() => { + + const request: ProductSearchRequest = baseProductBuilder() + .searchConstraints(constraints => constraints.setResultMustHaveVariantConstraint({ exceptWhenProductHasNoVariants: true })) + .build(); + + const result = await searcher.searchProducts(request); + + expect(result?.hits).toBeGreaterThan(0); +}); diff --git a/packages/client/tests/unit-tests/builders/search/productSearchBuilder.unit.test.ts b/packages/client/tests/unit-tests/builders/search/productSearchBuilder.unit.test.ts index f63cb2f..dc8439d 100644 --- a/packages/client/tests/unit-tests/builders/search/productSearchBuilder.unit.test.ts +++ b/packages/client/tests/unit-tests/builders/search/productSearchBuilder.unit.test.ts @@ -94,4 +94,14 @@ test('variantSearchSettings', () => { .build(); expect(subject.settings?.variantSettings?.excludeResultsWithoutVariant).toBe(true); +}); + +test('resultMustHaveVariantConstraint', () => { + const subject: ProductSearchRequest = baseBuilder() + .searchConstraints(s => s.setResultMustHaveVariantConstraint({ + exceptWhenProductHasNoVariants: true, + })) + .build(); + + expect(subject.settings?.resultConstraint?.exceptWhenProductHasNoVariants).toBe(true); }); \ No newline at end of file