diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 4365e4f6f83..9792c1acf43 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -3,3 +3,4 @@ a8ec45c8ea4ba559247b654d01b0d35b21a68865 430a1a0a5dd4efe78e21526c37bec9dbce036401 + diff --git a/api-java-mixin.raml b/api-java-mixin.raml index e30fe47bd6f..5ebce4f350c 100644 --- a/api-java-mixin.raml +++ b/api-java-mixin.raml @@ -1602,6 +1602,9 @@ types: (java-implements): 'ByProjectKeyProductProjectionsGetMixin' /search: + get: + (java-implements): + 'ByProjectKeyProductProjectionsSearchGetMixin' post: (java-implements): 'ByProjectKeyProductProjectionsSearchPostMixin' /product-selections: diff --git a/commercetools/commercetools-sdk-java-api/src/main/java-generated/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchGet.java b/commercetools/commercetools-sdk-java-api/src/main/java-generated/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchGet.java index 2b4335266f1..e9e612c75de 100644 --- a/commercetools/commercetools-sdk-java-api/src/main/java-generated/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchGet.java +++ b/commercetools/commercetools-sdk-java-api/src/main/java-generated/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchGet.java @@ -37,7 +37,8 @@ @Generated(value = "io.vrap.rmf.codegen.rendering.CoreCodeGenerator", comments = "https://github.com/commercetools/rmf-codegen") public class ByProjectKeyProductProjectionsSearchGet extends TypeApiMethod - implements com.commercetools.api.client.SortableTrait, + implements ByProjectKeyProductProjectionsSearchGetMixin, + com.commercetools.api.client.SortableTrait, com.commercetools.api.client.PagingTrait, com.commercetools.api.client.ProjectionselectingTrait, com.commercetools.api.client.PriceselectingTrait, diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchGetMixin.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchGetMixin.java new file mode 100644 index 00000000000..3cfbccf3c21 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchGetMixin.java @@ -0,0 +1,47 @@ + +package com.commercetools.api.client; + +import java.util.function.Function; + +import com.commercetools.api.search.products.FacetExpression; +import com.commercetools.api.search.products.FilterExpression; +import com.commercetools.api.search.products.ProductFacetExpressionBuilder; +import com.commercetools.api.search.products.ProductFilterExpressionBuilder; + +public interface ByProjectKeyProductProjectionsSearchGetMixin { + public ByProjectKeyProductProjectionsSearchGet addFilter(final TValue filter); + + public ByProjectKeyProductProjectionsSearchGet addFilterFacets(final TValue filterFacets); + + public ByProjectKeyProductProjectionsSearchGet addFilterQuery(final TValue filterQuery); + + public ByProjectKeyProductProjectionsSearchGet addFacet(final TValue facet); + + default ProductFilterExpressionBuilder filterDsl() { + return new ProductFilterExpressionBuilder(); + } + + default ProductFacetExpressionBuilder facetDsl() { + return new ProductFacetExpressionBuilder(); + } + + default ByProjectKeyProductProjectionsSearchGet filter( + Function fn) { + return addFilter(fn.apply(filterDsl()).render()); + } + + default ByProjectKeyProductProjectionsSearchGet filterFacets( + Function fn) { + return addFilterFacets(fn.apply(filterDsl()).render()); + } + + default ByProjectKeyProductProjectionsSearchGet filterQuery( + Function fn) { + return addFilterQuery(fn.apply(filterDsl()).render()); + } + + default ByProjectKeyProductProjectionsSearchGet facet( + Function> fn) { + return addFacet(fn.apply(facetDsl()).render()); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchPostMixin.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchPostMixin.java index a1d7bef5bce..a55a394414e 100644 --- a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchPostMixin.java +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/ByProjectKeyProductProjectionsSearchPostMixin.java @@ -7,6 +7,11 @@ import java.util.function.Supplier; import java.util.stream.Collectors; +import com.commercetools.api.search.products.FacetExpression; +import com.commercetools.api.search.products.FilterExpression; +import com.commercetools.api.search.products.ProductFacetExpressionBuilder; +import com.commercetools.api.search.products.ProductFilterExpressionBuilder; + import io.vrap.rmf.base.client.ApiMethod; public interface ByProjectKeyProductProjectionsSearchPostMixin { @@ -1654,4 +1659,32 @@ public default ByProjectKeyProductProjectionsSearchPost addText(final S .map(s -> new ApiMethod.ParamEntry<>(placeholderName, s.toString())) .collect(Collectors.toList())); } + + default ProductFilterExpressionBuilder filterDsl() { + return new ProductFilterExpressionBuilder(); + } + + default ProductFacetExpressionBuilder facetDsl() { + return new ProductFacetExpressionBuilder(); + } + + default ByProjectKeyProductProjectionsSearchPost filter( + Function fn) { + return addFilter(fn.apply(filterDsl()).render()); + } + + default ByProjectKeyProductProjectionsSearchPost filterFacets( + Function fn) { + return addFilterFacets(fn.apply(filterDsl()).render()); + } + + default ByProjectKeyProductProjectionsSearchPost filterQuery( + Function fn) { + return addFilterQuery(fn.apply(filterDsl()).render()); + } + + default ByProjectKeyProductProjectionsSearchPost facet( + Function> fn) { + return addFacet(fn.apply(facetDsl()).render()); + } } diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/Identifiable.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/Identifiable.java index 90d3734adff..185284d5137 100644 --- a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/Identifiable.java +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/Identifiable.java @@ -11,4 +11,8 @@ public interface Identifiable { * @return ID */ String getId(); + + static Identifiable of(final String id) { + return new SimpleIdentifiable<>(id); + } } diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/SimpleIdentifiable.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/SimpleIdentifiable.java new file mode 100644 index 00000000000..40738b3a9bb --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/SimpleIdentifiable.java @@ -0,0 +1,17 @@ + +package com.commercetools.api.models; + +public class SimpleIdentifiable implements Identifiable { + + private final String id; + + public SimpleIdentifiable(String id) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/common/CurrencyUtils.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/common/CurrencyUtils.java index 8e8cd0ceb06..1c3e0018d94 100644 --- a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/common/CurrencyUtils.java +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/models/common/CurrencyUtils.java @@ -8,7 +8,7 @@ import org.javamoney.moneta.spi.JDKCurrencyProvider; -final class CurrencyUtils { +public final class CurrencyUtils { static final JDKCurrencyProvider CURRENCY_PROVIDER = new JDKCurrencyProvider(); public static CurrencyUnit ofCode(final String currencyCode) { diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/CategoryTermFacetExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/CategoryTermFacetExpression.java new file mode 100644 index 00000000000..634f9d3eb79 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/CategoryTermFacetExpression.java @@ -0,0 +1,71 @@ + +package com.commercetools.api.search.products; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import com.commercetools.api.models.Identifiable; +import com.commercetools.api.models.category.Category; + +public class CategoryTermFacetExpression extends TermFacetExpression { + + public CategoryTermFacetExpression(PathExpression expression) { + super(expression, TermFormatter::format); + } + + public CategoryTermFacetExpression(PathExpression expression, List term) { + super(expression, term, TermFormatter::format); + } + + public CategoryTermFacetExpression is(String value) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + expressions.add(formatter().apply(value)); + return expressions; + }).orElse(Collections.singletonList(formatter().apply(value))); + return new CategoryTermFacetExpression(expression(), terms); + } + + public CategoryTermFacetExpression is(Identifiable value) { + return is(value.getId()); + } + + public CategoryTermFacetExpression subTree(String value) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + expressions.add( + ContainerExpression.of().parent(ConstantExpression.of("subTree")).inner(formatter().apply(value))); + return expressions; + }) + .orElse(Collections.singletonList( + ContainerExpression.of().parent(ConstantExpression.of("subTree")).inner(formatter().apply(value)))); + return new CategoryTermFacetExpression(expression(), terms); + } + + public CategoryTermFacetExpression subTree(Identifiable value) { + return subTree(value.getId()); + } + + public CategoryTermFacetExpression isIn(Iterable values) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + values.forEach(v -> expressions.add(formatter().apply(v))); + return expressions; + }).orElse(StreamSupport.stream(values.spliterator(), false).map(formatter()).collect(Collectors.toList())); + + return new CategoryTermFacetExpression(expression(), terms); + } + + public CategoryTermFacetExpression containsAny(Iterable> values) { + return isIn( + StreamSupport.stream(values.spliterator(), false).map(Identifiable::getId).collect(Collectors.toList())); + } + + public static CategoryTermFacetExpression of(PathExpression expression) { + return new CategoryTermFacetExpression(expression); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/CategoryTermFilterExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/CategoryTermFilterExpression.java new file mode 100644 index 00000000000..5c2d7eea311 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/CategoryTermFilterExpression.java @@ -0,0 +1,68 @@ + +package com.commercetools.api.search.products; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import com.commercetools.api.models.Identifiable; +import com.commercetools.api.models.category.Category; + +public class CategoryTermFilterExpression extends TermFilterExpression { + + public CategoryTermFilterExpression(PathExpression expression) { + super(expression, TermFormatter::format); + } + + public CategoryTermFilterExpression(PathExpression expression, List term) { + super(expression, term, TermFormatter::format); + } + + public CategoryTermFilterExpression is(String value) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + expressions.add(formatter().apply(value)); + return expressions; + }).orElse(Collections.singletonList(formatter().apply(value))); + return new CategoryTermFilterExpression(expression(), terms); + } + + public CategoryTermFilterExpression is(Identifiable value) { + return is(value.getId()); + } + + public CategoryTermFilterExpression subTree(String value) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + expressions.add( + ContainerExpression.of().parent(ConstantExpression.of("subTree")).inner(formatter().apply(value))); + return expressions; + }) + .orElse(Collections.singletonList( + ContainerExpression.of().parent(ConstantExpression.of("subTree")).inner(formatter().apply(value)))); + return new CategoryTermFilterExpression(expression(), terms); + } + + public CategoryTermFilterExpression subTree(Identifiable value) { + return subTree(value.getId()); + } + + public CategoryTermFilterExpression isIn(Iterable values) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + values.forEach(v -> expressions.add(formatter().apply(v))); + return expressions; + }).orElse(StreamSupport.stream(values.spliterator(), false).map(formatter()).collect(Collectors.toList())); + + return new CategoryTermFilterExpression(expression(), terms); + } + + public CategoryTermFilterExpression containsAny(Iterable> values) { + return isIn( + StreamSupport.stream(values.spliterator(), false).map(Identifiable::getId).collect(Collectors.toList())); + } + + public static CategoryTermFilterExpression of(PathExpression expression) { + return new CategoryTermFilterExpression(expression); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ConstantExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ConstantExpression.java new file mode 100644 index 00000000000..196f23854f9 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ConstantExpression.java @@ -0,0 +1,23 @@ + +package com.commercetools.api.search.products; + +public class ConstantExpression implements FilterExpression { + private final String value; + + public ConstantExpression(String value) { + this.value = value; + } + + public String value() { + return value; + } + + @Override + public String render() { + return value; + } + + public static ConstantExpression of(String value) { + return new ConstantExpression(value); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ContainerExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ContainerExpression.java new file mode 100644 index 00000000000..08418bb6fbb --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ContainerExpression.java @@ -0,0 +1,76 @@ + +package com.commercetools.api.search.products; + +import java.util.Objects; + +public class ContainerExpression implements FilterExpression { + private final FilterExpression parent; + + private final FilterExpression inner; + + private final boolean renderInnerWithoutParentheses; + + public ContainerExpression() { + parent = null; + inner = null; + renderInnerWithoutParentheses = false; + } + + public ContainerExpression(final FilterExpression parent, final FilterExpression inner) { + this.parent = parent; + this.inner = inner; + this.renderInnerWithoutParentheses = false; + } + + public ContainerExpression(final FilterExpression parent, final FilterExpression inner, + final boolean renderInnerWithoutParentheses) { + this.parent = parent; + this.inner = inner; + this.renderInnerWithoutParentheses = renderInnerWithoutParentheses; + } + + public FilterExpression parent() { + return parent; + } + + public FilterExpression inner() { + return inner; + } + + public boolean renderInnerWithOutParentheses() { + return renderInnerWithoutParentheses; + } + + public ContainerExpression parent(final FilterExpression parent) { + return new ContainerExpression(parent, inner, renderInnerWithoutParentheses); + } + + public ContainerExpression inner(final FilterExpression element) { + return new ContainerExpression(parent, element, renderInnerWithoutParentheses); + } + + public ContainerExpression renderInnerWithOutParentheses(final boolean renderInnerWithoutParentheses) { + return new ContainerExpression(parent, inner, renderInnerWithoutParentheses); + } + + @Override + public String render() { + if (renderInnerWithoutParentheses) { + return parent().render() + " " + Objects.requireNonNull(inner).render(); + } + return parent().render() + "(" + Objects.requireNonNull(inner).render() + ")"; + } + + public static ContainerExpression of() { + return new ContainerExpression(); + } + + public static ContainerExpression of(final FilterExpression parent, final FilterExpression inner) { + return new ContainerExpression(parent, inner); + } + + public static ContainerExpression of(final FilterExpression parent, final FilterExpression inner, + final boolean renderInnerWithoutParentheses) { + return new ContainerExpression(parent, inner, renderInnerWithoutParentheses); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ExistsTermFilterExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ExistsTermFilterExpression.java new file mode 100644 index 00000000000..c9a47c60bd0 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ExistsTermFilterExpression.java @@ -0,0 +1,28 @@ + +package com.commercetools.api.search.products; + +import java.util.*; + +public class ExistsTermFilterExpression extends TermFilterExpression { + + public ExistsTermFilterExpression(PathExpression expression) { + super(expression, TermFormatter::format); + } + + public ExistsTermFilterExpression(PathExpression expression, List term) { + super(expression, term, TermFormatter::format); + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression(), + Collections.singletonList(ConstantExpression.of("missing"))); + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression(), Collections.singletonList(ConstantExpression.of("exists"))); + } + + public static ExistsTermFilterExpression of(PathExpression expression) { + return new ExistsTermFilterExpression(expression); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ExistsTermFilterExpressionBuilder.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ExistsTermFilterExpressionBuilder.java new file mode 100644 index 00000000000..b180f34dbcc --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ExistsTermFilterExpressionBuilder.java @@ -0,0 +1,25 @@ + +package com.commercetools.api.search.products; + +import java.util.Collections; + +public class ExistsTermFilterExpressionBuilder implements FilterExpression { + + private final PathExpression expression; + + public ExistsTermFilterExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression, Collections.singletonList(ConstantExpression.of("missing"))); + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression, Collections.singletonList(ConstantExpression.of("exists"))); + } + + public static ExistsTermFilterExpressionBuilder of(PathExpression expression) { + return new ExistsTermFilterExpressionBuilder(expression); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/FacetExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/FacetExpression.java new file mode 100644 index 00000000000..ceba69da100 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/FacetExpression.java @@ -0,0 +1,9 @@ + +package com.commercetools.api.search.products; + +public interface FacetExpression extends FilterExpression { + + FacetExpression countingProducts(); + + FacetExpression alias(String alias); +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/FilterExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/FilterExpression.java new file mode 100644 index 00000000000..e45bef295d6 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/FilterExpression.java @@ -0,0 +1,8 @@ + +package com.commercetools.api.search.products; + +public interface FilterExpression { + default String render() { + return ""; + }; +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/PathExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/PathExpression.java new file mode 100644 index 00000000000..e6a69c968ea --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/PathExpression.java @@ -0,0 +1,56 @@ + +package com.commercetools.api.search.products; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class PathExpression implements FilterExpression { + private final List paths; + + public PathExpression() { + paths = new ArrayList<>(); + } + + public PathExpression(FilterExpression path) { + this.paths = Collections.singletonList(path); + } + + public PathExpression(List paths) { + this.paths = paths; + } + + public List paths() { + return paths; + } + + public PathExpression add(String element) { + List p = new ArrayList<>(paths); + p.add(ConstantExpression.of(element)); + return new PathExpression(p); + } + + public PathExpression add(FilterExpression element) { + List p = new ArrayList<>(paths); + p.add(element); + return new PathExpression(p); + } + + @Override + public String render() { + return paths.stream().map(FilterExpression::render).collect(Collectors.joining(".")); + } + + public static PathExpression of() { + return new PathExpression(); + } + + public static PathExpression of(String parent) { + return new PathExpression(ConstantExpression.of(parent)); + } + + public static PathExpression of(FilterExpression parent) { + return new PathExpression(parent); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ProductFacetExpressionBuilder.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ProductFacetExpressionBuilder.java new file mode 100644 index 00000000000..6c9276190a4 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ProductFacetExpressionBuilder.java @@ -0,0 +1,228 @@ + +package com.commercetools.api.search.products; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.Locale; + +import javax.money.CurrencyUnit; + +import com.commercetools.api.models.Identifiable; +import com.commercetools.api.models.channel.Channel; + +public class ProductFacetExpressionBuilder { + public CategoriesFacetExpressionBuilder categories() { + return new CategoriesFacetExpressionBuilder(); + } + + public VariantsFacetExpressionBuilder variants() { + return new VariantsFacetExpressionBuilder(); + } + + public ReviewRatingStatisticsFacetExpressionBuilder reviewRatingStatistics() { + return new ReviewRatingStatisticsFacetExpressionBuilder(); + } + + public static ProductFacetExpressionBuilder of() { + return new ProductFacetExpressionBuilder(); + } + + public static class CategoriesFacetExpressionBuilder { + + PathExpression expression; + + public CategoriesFacetExpressionBuilder() { + this.expression = PathExpression.of("categories"); + } + + public CategoryTermFacetExpression id() { + return CategoryTermFacetExpression.of(expression.add("id")); + } + } + + public static class ReviewRatingStatisticsFacetExpressionBuilder { + PathExpression expression; + + public ReviewRatingStatisticsFacetExpressionBuilder() { + this.expression = PathExpression.of("reviewRatingStatistics"); + } + + public TermFilterExpression averageRating() { + return TermFilterExpression.of(expression.add("averageRating"), TermFormatter::format); + } + + public TermFilterExpression highestRating() { + return TermFilterExpression.of(expression.add("highestRating"), TermFormatter::format); + } + + public TermFilterExpression lowestRating() { + return TermFilterExpression.of(expression.add("lowestRating"), TermFormatter::format); + } + + public TermFilterExpression count() { + return TermFilterExpression.of(expression.add("count"), TermFormatter::format); + } + } + + public static class VariantsFacetExpressionBuilder { + + PathExpression expression; + + public VariantsFacetExpressionBuilder() { + this.expression = PathExpression.of("variants"); + } + + public AttributesFacetExpressionBuilder attribute() { + return new AttributesFacetExpressionBuilder(expression); + } + + public AvailabilityFacetExpressionBuilder availability() { + return new AvailabilityFacetExpressionBuilder(expression.add("availability")); + } + + public PriceFacetExpressionBuilder price() { + return new PriceFacetExpressionBuilder(expression.add("price")); + } + + public PriceFacetExpressionBuilder scopedPrice() { + return new PriceFacetExpressionBuilder(expression.add("price")); + } + } + + public static class ScopedPriceFacetExpressionBuilder { + PathExpression expression; + + public ScopedPriceFacetExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public PriceFacetExpressionBuilder currentValue() { + return new PriceFacetExpressionBuilder(expression.add("currentValue")); + } + } + + public static class PriceFacetExpressionBuilder { + PathExpression expression; + + public PriceFacetExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public RangeFilterExpressionBuilder centAmount() { + return RangeFilterExpressionBuilder.of(expression.add("centAmount"), TermFormatter::format); + } + } + + public static class AvailabilityFacetExpressionBuilder { + PathExpression expression; + + public AvailabilityFacetExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public RangeFilterExpressionBuilder availableQuantity() { + return RangeFilterExpressionBuilder.of(expression.add("availableQuantity"), TermFormatter::format); + } + + public AvailabilityFacetExpressionBuilder channel(Identifiable channel) { + return channel(channel.getId()); + } + + public AvailabilityFacetExpressionBuilder channel(String channel) { + return new AvailabilityFacetExpressionBuilder(expression.add("channels").add(channel)); + } + } + + public static class AttributesFacetExpressionBuilder { + PathExpression expression; + + public AttributesFacetExpressionBuilder(PathExpression expression) { + this.expression = expression.add("attributes"); + } + + public TermFacetExpression ofText(final String name) { + return TermFacetExpression.of(expression.add(name), TermFormatter::format); + } + + public RangeFacetExpressionBuilder ofDate(final String name) { + return RangeFacetExpressionBuilder.of(expression.add(name), TermFormatter::format); + } + + public RangeFacetExpressionBuilder ofTime(final String name) { + return RangeFacetExpressionBuilder.of(expression.add(name), TermFormatter::format); + } + + public RangeFacetExpressionBuilder ofDatetime(final String name) { + return RangeFacetExpressionBuilder.of(expression.add(name), TermFormatter::format); + } + + public TermFacetExpression ofBool(final String name) { + return TermFacetExpression.of(expression.add(name), TermFormatter::format); + } + + public RangeFacetExpressionBuilder ofNumber(final String name) { + return RangeFacetExpressionBuilder.of(expression.add(name), TermFormatter::format); + } + + public RangeFacetExpressionBuilder ofLong(final String name) { + return RangeFacetExpressionBuilder.of(expression.add(name), TermFormatter::format); + } + + public TermFacetExpression ofLocalizedString(final String name, final String language) { + return TermFacetExpression.of(expression.add(name).add(language), TermFormatter::format); + } + + public AttributesEnumFacetExpressionBuilder ofEnum(final String name) { + return new AttributesEnumFacetExpressionBuilder(expression.add(name)); + } + + public AttributesMoneyFacetExpressionBuilder ofMoney(final String name) { + return new AttributesMoneyFacetExpressionBuilder(expression.add(name)); + } + } + + public static class AttributesEnumFacetExpressionBuilder { + PathExpression expression; + + public AttributesEnumFacetExpressionBuilder(final PathExpression expression) { + this.expression = expression; + } + + public TermFacetExpression key() { + return TermFacetExpression.of(expression.add("key"), TermFormatter::format); + } + + public TermFacetExpression label() { + return TermFacetExpression.of(expression.add("label"), TermFormatter::format); + } + + public TermFacetExpression label(final String language) { + return TermFacetExpression.of(expression.add("label").add(language), TermFormatter::format); + } + + public TermFacetExpression label(final Locale locale) { + return TermFacetExpression.of(expression.add("label").add(locale.toLanguageTag()), TermFormatter::format); + } + } + + public static class AttributesMoneyFacetExpressionBuilder { + PathExpression expression; + + public AttributesMoneyFacetExpressionBuilder(final PathExpression expression) { + this.expression = expression; + } + + public RangeFacetExpressionBuilder centAmount() { + return RangeFacetExpressionBuilder.of(expression.add("centAmount"), TermFormatter::format); + } + + public TermFacetExpression currencyCode() { + return TermFacetExpression.of(expression.add("currencyCode"), TermFormatter::format); + } + + public TermFacetExpression currency() { + return TermFacetExpression.of(expression.add("currencyCode"), TermFormatter::format); + } + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ProductFilterExpressionBuilder.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ProductFilterExpressionBuilder.java new file mode 100644 index 00000000000..0b0d31c22f0 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ProductFilterExpressionBuilder.java @@ -0,0 +1,419 @@ + +package com.commercetools.api.search.products; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.Locale; + +import javax.money.CurrencyUnit; + +import com.commercetools.api.models.Identifiable; +import com.commercetools.api.models.category.Category; +import com.commercetools.api.models.channel.Channel; +import com.commercetools.api.models.product_type.ProductType; +import com.commercetools.api.models.state.State; +import com.commercetools.api.models.tax_category.TaxCategory; + +public class ProductFilterExpressionBuilder { + + public CategoriesFilterExpressionBuilder categories() { + return new CategoriesFilterExpressionBuilder(); + } + + public ReferencableFilterExpressionBuilder productType() { + return new ReferencableFilterExpressionBuilder<>("productType"); + } + + public ReferencableFilterExpressionBuilder taxCategory() { + return new ReferencableFilterExpressionBuilder<>("taxCategory"); + } + + public ReferencableFilterExpressionBuilder state() { + return new ReferencableFilterExpressionBuilder<>("state"); + } + + public TermFilterExpressionBuilder key() { + return TermFilterExpressionBuilder.of(PathExpression.of("key"), TermFormatter::format); + } + + public VariantsFilterExpressionBuilder variants() { + return new VariantsFilterExpressionBuilder(); + } + + public ReviewRatingStatisticsFilterExpressionBuilder reviewRatingStatistics() { + return new ReviewRatingStatisticsFilterExpressionBuilder(); + } + + public RangeFilterExpressionBuilder createdAt() { + return RangeFilterExpressionBuilder.of(PathExpression.of("createdAt"), TermFormatter::format); + } + + public RangeFilterExpressionBuilder lastModifiedAt() { + return RangeFilterExpressionBuilder.of(PathExpression.of("lastModifiedAt"), TermFormatter::format); + } + + public TermFilterExpressionBuilder searchKeywords(Locale locale) { + return searchKeywords(locale.toLanguageTag()); + } + + public TermFilterExpressionBuilder searchKeywords(String locale) { + return TermFilterExpressionBuilder.of(PathExpression.of("searchKeywords").add(locale).add("text"), + TermFormatter::format); + } + + public static ProductFilterExpressionBuilder of() { + return new ProductFilterExpressionBuilder(); + } + + public static class CategoriesFilterExpressionBuilder { + + PathExpression expression; + + public CategoriesFilterExpressionBuilder() { + this.expression = PathExpression.of("categories"); + } + + public CategoryTermFilterExpressionBuilder id() { + return CategoryTermFilterExpressionBuilder.of(expression.add("id")); + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression).exists(); + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression).missing(); + } + } + + public static class ReferencableFilterExpressionBuilder { + + PathExpression expression; + + public ReferencableFilterExpressionBuilder(String path) { + this.expression = PathExpression.of(ConstantExpression.of(path)); + } + + public ReferencableFilterExpressionBuilder(PathExpression expression) { + this.expression = PathExpression.of(expression); + } + + public ReferencableTermFilterExpressionBuilder id() { + return ReferencableTermFilterExpressionBuilder.of(expression.add("id")); + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression).exists(); + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression).missing(); + } + } + + public static class VariantsFilterExpressionBuilder { + PathExpression expression; + + public VariantsFilterExpressionBuilder() { + this.expression = PathExpression.of("variants"); + } + + public TermFilterExpressionBuilder key() { + return TermFilterExpressionBuilder.of(expression.add("key"), TermFormatter::format); + } + + public TermFilterExpressionBuilder sku() { + return TermFilterExpressionBuilder.of(expression.add("sku"), TermFormatter::format); + } + + public PriceFilterExpressionBuilder price() { + return new PriceFilterExpressionBuilder(expression.add("price")); + } + + public TermFilterExpressionBuilder scopedPriceDiscounted() { + return TermFilterExpressionBuilder.of(expression.add("scopedPriceDiscounted"), TermFormatter::format); + } + + public ScopedPriceFilterExpressionBuilder scopedPrice() { + return new ScopedPriceFilterExpressionBuilder(expression.add("scopedPrice")); + } + + public ExistsTermFilterExpressionBuilder prices() { + return ExistsTermFilterExpressionBuilder.of(expression.add("prices")); + } + + public AvailabilityFilterExpressionBuilder availability() { + return new AvailabilityFilterExpressionBuilder(expression.add("availability")); + } + + public AttributeFilterExpressionBuilder attribute(String name) { + return new AttributeFilterExpressionBuilder(expression.add("attributes").add(name)); + } + } + + public static class ReviewRatingStatisticsFilterExpressionBuilder { + PathExpression expression; + + public ReviewRatingStatisticsFilterExpressionBuilder() { + this.expression = PathExpression.of("reviewRatingStatistics"); + } + + public RangeFilterExpressionBuilder averageRating() { + return RangeFilterExpressionBuilder.of(expression.add("averageRating"), TermFormatter::format); + } + + public RangeFilterExpressionBuilder highestRating() { + return RangeFilterExpressionBuilder.of(expression.add("highestRating"), TermFormatter::format); + } + + public RangeFilterExpressionBuilder lowestRating() { + return RangeFilterExpressionBuilder.of(expression.add("lowestRating"), TermFormatter::format); + } + + public RangeFilterExpressionBuilder count() { + return RangeFilterExpressionBuilder.of(expression.add("count"), TermFormatter::format); + } + } + + public static class AvailabilityFilterExpressionBuilder { + PathExpression expression; + + public AvailabilityFilterExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public TermFilterExpressionBuilder isOnStock() { + return TermFilterExpressionBuilder.of(expression.add("isOnStock"), TermFormatter::format); + } + + public RangeFilterExpressionBuilder availableQuantity() { + return RangeFilterExpressionBuilder.of(expression.add("availableQuantity"), TermFormatter::format); + } + + public AvailabilityFilterExpressionBuilder channel(Identifiable channel) { + return channel(channel.getId()); + } + + public AvailabilityFilterExpressionBuilder channel(String channel) { + return new AvailabilityFilterExpressionBuilder(expression.add("channels").add(channel)); + } + + public ReferencableTermFilterExpressionBuilder isOnStockInChannels() { + return ReferencableTermFilterExpressionBuilder.of(expression.add("isOnStockInChannels")); + } + } + + public static class PriceFilterExpressionBuilder { + PathExpression expression; + + public PriceFilterExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public RangeFilterExpressionBuilder centAmount() { + return RangeFilterExpressionBuilder.of(expression.add("centAmount"), TermFormatter::format); + } + + public TermFilterExpression currencyCode() { + return TermFilterExpression.of(expression.add("currencyCode"), TermFormatter::format); + } + + public TermFilterExpression currency() { + return TermFilterExpression.of(expression.add("currencyCode"), TermFormatter::format); + } + } + + public static class ScopedPriceFilterExpressionBuilder { + PathExpression expression; + + public ScopedPriceFilterExpressionBuilder(PathExpression expression) { + this.expression = PathExpression.of(expression); + } + + public PriceFilterExpressionBuilder value() { + return new PriceFilterExpressionBuilder(expression.add("value")); + } + + public PriceFilterExpressionBuilder currentValue() { + return new PriceFilterExpressionBuilder(expression.add("currentValue")); + } + + public DiscountedPriceFilterExpressionBuilder discounted() { + return new DiscountedPriceFilterExpressionBuilder(expression.add("discounted")); + } + + public TermFilterExpression currency() { + return TermFilterExpression.of(expression.add("currencyCode"), TermFormatter::format); + } + + } + + public static class DiscountedPriceFilterExpressionBuilder { + PathExpression expression; + + public DiscountedPriceFilterExpressionBuilder(PathExpression expression) { + this.expression = PathExpression.of(expression); + } + + public PriceFilterExpressionBuilder value() { + return new PriceFilterExpressionBuilder(expression.add("value")); + } + + } + + public static class CategoryTermFilterExpressionBuilder { + + PathExpression expression; + + public CategoryTermFilterExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public CategoryTermFilterExpression is(String value) { + return CategoryTermFilterExpression.of(expression).is(value); + } + + public CategoryTermFilterExpression is(Identifiable value) { + return is(value.getId()); + } + + public CategoryTermFilterExpression subTree(String value) { + return CategoryTermFilterExpression.of(expression).subTree(value); + } + + public CategoryTermFilterExpression subTree(Identifiable value) { + return subTree(value.getId()); + } + + public CategoryTermFilterExpression isIn(Iterable values) { + return CategoryTermFilterExpression.of(expression).isIn(values); + } + + public CategoryTermFilterExpression containsAny(Iterable> values) { + return CategoryTermFilterExpression.of(expression).containsAny(values); + } + + public static CategoryTermFilterExpressionBuilder of(PathExpression expression) { + return new CategoryTermFilterExpressionBuilder(expression); + } + } + + public static class ReferencableTermFilterExpressionBuilder { + + PathExpression expression; + + public ReferencableTermFilterExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public ReferenceableTermFilterExpression is(String value) { + return ReferenceableTermFilterExpression. of(expression).is(value); + } + + public ReferenceableTermFilterExpression is(Identifiable value) { + return is(value.getId()); + } + + public ReferenceableTermFilterExpression isIn(Iterable values) { + return ReferenceableTermFilterExpression. of(expression).isIn(values); + } + + public ReferenceableTermFilterExpression containsAny(Iterable> values) { + return ReferenceableTermFilterExpression. of(expression).containsAny(values); + } + + public static ReferencableTermFilterExpressionBuilder of(PathExpression expression) { + return new ReferencableTermFilterExpressionBuilder<>(expression); + } + } + + public static class AttributeFilterExpressionBuilder { + PathExpression expression; + + public AttributeFilterExpressionBuilder(PathExpression expression) { + this.expression = expression; + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression).exists(); + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression).missing(); + } + + public TermFilterExpressionBuilder asBoolean() { + return new TermFilterExpressionBuilder<>(expression, TermFormatter::format); + } + + public RangeFilterExpressionBuilder asLong() { + return new RangeFilterExpressionBuilder<>(expression, TermFormatter::format); + } + + public RangeFilterExpressionBuilder asDouble() { + return new RangeFilterExpressionBuilder<>(expression, TermFormatter::format); + } + + public TermFilterExpressionBuilder asString() { + return new TermFilterExpressionBuilder<>(expression, TermFormatter::format); + } + + public RangeFilterExpressionBuilder asDateTime() { + return new RangeFilterExpressionBuilder<>(expression, TermFormatter::format); + } + + public RangeFilterExpressionBuilder asDate() { + return new RangeFilterExpressionBuilder<>(expression, TermFormatter::format); + } + + public RangeFilterExpressionBuilder asTime() { + return new RangeFilterExpressionBuilder<>(expression, TermFormatter::format); + } + + public PriceFilterExpressionBuilder asMoney() { + return new PriceFilterExpressionBuilder(expression); + } + + public AttributeReferenceTermFilterExpressionBuilder asReference() { + return new AttributeReferenceTermFilterExpressionBuilder(expression); + } + + public EnumTermFilterExpressionBuilder asEnum() { + return new EnumTermFilterExpressionBuilder(expression); + } + } + + public static class EnumTermFilterExpressionBuilder { + PathExpression expression; + + public EnumTermFilterExpressionBuilder(PathExpression expression) { + this.expression = PathExpression.of(expression); + } + + public TermFilterExpressionBuilder key() { + return new TermFilterExpressionBuilder<>(expression.add("key"), TermFormatter::format); + } + } + + public static class AttributeReferenceTermFilterExpressionBuilder { + + PathExpression expression; + + public AttributeReferenceTermFilterExpressionBuilder(PathExpression expression) { + this.expression = PathExpression.of(expression); + } + + public ReferencableTermFilterExpressionBuilder id() { + return new ReferencableFilterExpressionBuilder<>(expression).id(); + } + + public TermFilterExpressionBuilder typeId() { + return TermFilterExpressionBuilder.of(expression.add("typeId"), TermFormatter::format); + } + + public static AttributeReferenceTermFilterExpressionBuilder of(PathExpression expression) { + return new AttributeReferenceTermFilterExpressionBuilder(expression); + } + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeExpression.java new file mode 100644 index 00000000000..c2006f121de --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeExpression.java @@ -0,0 +1,37 @@ + +package com.commercetools.api.search.products; + +public class RangeExpression implements FilterExpression { + private final FilterExpression from; + private final FilterExpression to; + + public RangeExpression(FilterExpression from, FilterExpression to) { + this.from = from; + this.to = to; + } + + public FilterExpression from() { + return from; + } + + public FilterExpression to() { + return to; + } + + @Override + public String render() { + return String.format("(%s to %s)", from.render(), to.render()); + } + + public static RangeExpression from(FilterExpression from) { + return new RangeExpression(from, ConstantExpression.of("*")); + } + + public static RangeExpression to(FilterExpression to) { + return new RangeExpression(ConstantExpression.of("*"), to); + } + + public static RangeExpression of(FilterExpression from, FilterExpression to) { + return new RangeExpression(from, to); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFacetExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFacetExpression.java new file mode 100644 index 00000000000..8b7d3690aa0 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFacetExpression.java @@ -0,0 +1,119 @@ + +package com.commercetools.api.search.products; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class RangeFacetExpression implements FacetExpression { + + private final PathExpression expression; + + private final List ranges; + + private final Function formatter; + + private final boolean countingProducts; + + private final String alias; + + RangeFacetExpression(final PathExpression expression, final Function formatter) { + this.expression = expression; + this.ranges = null; + this.formatter = formatter; + this.alias = null; + this.countingProducts = false; + } + + RangeFacetExpression(final PathExpression expression, final List ranges, + final Function formatter) { + this.expression = expression; + this.ranges = ranges; + this.formatter = formatter; + this.alias = null; + this.countingProducts = false; + } + + RangeFacetExpression(final PathExpression expression, final List ranges, + final Function formatter, final String alias, final boolean countingProducts) { + this.expression = expression; + this.ranges = ranges; + this.formatter = formatter; + this.alias = alias; + this.countingProducts = countingProducts; + } + + PathExpression expression() { + return expression; + } + + List ranges() { + return ranges; + } + + Function formatter() { + return formatter; + } + + public RangeFacetExpression alias(final String alias) { + return new RangeFacetExpression<>(expression, ranges, formatter, alias, countingProducts); + } + + public RangeFacetExpression countingProducts() { + return new RangeFacetExpression<>(expression, ranges, formatter, alias, true); + } + + public RangeFacetExpression rangeFrom(T from) { + List terms = Optional.ofNullable(ranges).map(rangeList -> { + List expressions = new ArrayList<>(rangeList); + expressions.add(RangeExpression.from(formatter().apply(from))); + return expressions; + }).orElse(Collections.singletonList(RangeExpression.from(formatter().apply(from)))); + return new RangeFacetExpression<>(expression, terms, formatter, alias, countingProducts); + } + + public RangeFacetExpression rangeTo(T to) { + List terms = Optional.ofNullable(ranges).map(rangeList -> { + List expressions = new ArrayList<>(rangeList); + expressions.add(RangeExpression.to(formatter().apply(to))); + return expressions; + }).orElse(Collections.singletonList(RangeExpression.to(formatter().apply(to)))); + return new RangeFacetExpression<>(expression, terms, formatter, alias, countingProducts); + } + + public RangeFacetExpression range(T from, T to) { + List terms = Optional.ofNullable(ranges).map(rangeList -> { + List expressions = new ArrayList<>(rangeList); + expressions.add(RangeExpression.of(formatter().apply(from), formatter().apply(to))); + return expressions; + }).orElse(Collections.singletonList(RangeExpression.of(formatter().apply(from), formatter().apply(to)))); + return new RangeFacetExpression<>(expression, terms, formatter, alias, countingProducts); + } + + public static RangeFacetExpression of(final PathExpression expression, + final Function formatter) { + return new RangeFacetExpression<>(expression, formatter); + } + + public static RangeFacetExpression of(final PathExpression expression, final List ranges, + Function formatter) { + return new RangeFacetExpression<>(expression, ranges, formatter); + } + + public static RangeFacetExpression of(final PathExpression expression, final List ranges, + final Function formatter, final String alias, final boolean countingProducts) { + return new RangeFacetExpression<>(expression, ranges, formatter, alias, countingProducts); + } + + @Override + public String render() { + Objects.requireNonNull(ranges); + return expression.render() + ": range " + + ranges.stream().map(FilterExpression::render).collect(Collectors.joining(", ")) + renderMeta(); + } + + private String renderMeta() { + return Optional.ofNullable(alias).map(s -> String.format(" as %s", alias)).orElse("") + + (countingProducts ? " counting products" : ""); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFacetExpressionBuilder.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFacetExpressionBuilder.java new file mode 100644 index 00000000000..767c98f30f2 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFacetExpressionBuilder.java @@ -0,0 +1,51 @@ + +package com.commercetools.api.search.products; + +import java.util.Objects; +import java.util.function.Function; + +public class RangeFacetExpressionBuilder implements FilterExpression { + private final PathExpression expression; + private final Function formatter; + + public RangeFacetExpressionBuilder() { + this.expression = null; + this.formatter = null; + } + + public RangeFacetExpressionBuilder(PathExpression expression, Function formatter) { + this.expression = expression; + this.formatter = formatter; + } + + public TermFacetExpression is(T value) { + return TermFacetExpression.of(expression, formatter).is(value); + } + + public TermFacetExpression isIn(Iterable values) { + return TermFacetExpression.of(expression, formatter).isIn(values); + } + + public RangeFacetExpression rangeFrom(T from) { + return RangeFacetExpression.of(expression, formatter).rangeFrom(from); + } + + public RangeFacetExpression rangeTo(T to) { + return RangeFacetExpression.of(expression, formatter).rangeTo(to); + } + + public RangeFacetExpression range(T from, T to) { + return RangeFacetExpression.of(expression, formatter).range(from, to); + } + + @Override + public String render() { + Objects.requireNonNull(expression); + return expression.render(); + } + + public static RangeFacetExpressionBuilder of(PathExpression expression, + Function formatter) { + return new RangeFacetExpressionBuilder<>(expression, formatter); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFilterExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFilterExpression.java new file mode 100644 index 00000000000..8d36e8eca5d --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFilterExpression.java @@ -0,0 +1,91 @@ + +package com.commercetools.api.search.products; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class RangeFilterExpression implements FilterExpression { + + private final PathExpression expression; + + private final List ranges; + + private final Function formatter; + + public RangeFilterExpression(PathExpression expression, Function formatter) { + this.expression = expression; + this.ranges = null; + this.formatter = formatter; + } + + public RangeFilterExpression(PathExpression expression, List ranges, + Function formatter) { + this.expression = expression; + this.ranges = ranges; + this.formatter = formatter; + } + + PathExpression expression() { + return expression; + } + + List ranges() { + return ranges; + } + + Function formatter() { + return formatter; + } + + public RangeFilterExpression rangeFrom(T from) { + List terms = Optional.ofNullable(ranges).map(rangeList -> { + List expressions = new ArrayList<>(rangeList); + expressions.add(RangeExpression.from(formatter().apply(from))); + return expressions; + }).orElse(Collections.singletonList(RangeExpression.from(formatter().apply(from)))); + return RangeFilterExpression.of(expression, terms, formatter); + } + + public RangeFilterExpression rangeTo(T to) { + List terms = Optional.ofNullable(ranges).map(rangeList -> { + List expressions = new ArrayList<>(rangeList); + expressions.add(RangeExpression.to(formatter().apply(to))); + return expressions; + }).orElse(Collections.singletonList(RangeExpression.to(formatter().apply(to)))); + return RangeFilterExpression.of(expression, terms, formatter); + } + + public RangeFilterExpression range(T from, T to) { + List terms = Optional.ofNullable(ranges).map(rangeList -> { + List expressions = new ArrayList<>(rangeList); + expressions.add(RangeExpression.of(formatter().apply(from), formatter().apply(to))); + return expressions; + }).orElse(Collections.singletonList(RangeExpression.of(formatter().apply(from), formatter().apply(to)))); + return RangeFilterExpression.of(expression, terms, formatter); + } + + public static RangeFilterExpression of(PathExpression expression, Function formatter) { + return new RangeFilterExpression<>(expression, formatter); + } + + public static RangeFilterExpression of(PathExpression expression, List ranges, + Function formatter) { + return new RangeFilterExpression<>(expression, ranges, formatter); + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression).exists(); + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression).missing(); + } + + @Override + public String render() { + Objects.requireNonNull(ranges); + return expression.render() + ": range " + + ranges.stream().map(FilterExpression::render).collect(Collectors.joining(", ")); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFilterExpressionBuilder.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFilterExpressionBuilder.java new file mode 100644 index 00000000000..c77ece9288d --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/RangeFilterExpressionBuilder.java @@ -0,0 +1,44 @@ + +package com.commercetools.api.search.products; + +import java.util.function.Function; + +public class RangeFilterExpressionBuilder { + private final PathExpression expression; + private final Function formatter; + + public RangeFilterExpressionBuilder() { + this.expression = null; + this.formatter = null; + } + + public RangeFilterExpressionBuilder(PathExpression expression, Function formatter) { + this.expression = expression; + this.formatter = formatter; + } + + public TermFilterExpression is(T value) { + return TermFilterExpression.of(expression, formatter).is(value); + } + + public TermFilterExpression isIn(Iterable values) { + return TermFilterExpression.of(expression, formatter).isIn(values); + } + + public RangeFilterExpression rangeFrom(T from) { + return RangeFilterExpression.of(expression, formatter).rangeFrom(from); + } + + public RangeFilterExpression rangeTo(T to) { + return RangeFilterExpression.of(expression, formatter).rangeTo(to); + } + + public RangeFilterExpression range(T from, T to) { + return RangeFilterExpression.of(expression, formatter).range(from, to); + } + + public static RangeFilterExpressionBuilder of(PathExpression expression, + Function formatter) { + return new RangeFilterExpressionBuilder<>(expression, formatter); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ReferenceableTermFilterExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ReferenceableTermFilterExpression.java new file mode 100644 index 00000000000..b9bf74e1bc1 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/ReferenceableTermFilterExpression.java @@ -0,0 +1,54 @@ + +package com.commercetools.api.search.products; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import com.commercetools.api.models.Identifiable; + +public class ReferenceableTermFilterExpression extends TermFilterExpression { + + public ReferenceableTermFilterExpression(PathExpression expression) { + super(expression, TermFormatter::format); + } + + public ReferenceableTermFilterExpression(PathExpression expression, List term) { + super(expression, term, TermFormatter::format); + } + + public ReferenceableTermFilterExpression is(String value) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + expressions.add(formatter().apply(value)); + return expressions; + }).orElse(Collections.singletonList(formatter().apply(value))); + return new ReferenceableTermFilterExpression<>(expression(), terms); + } + + public ReferenceableTermFilterExpression is(Identifiable value) { + return is(value.getId()); + } + + public ReferenceableTermFilterExpression isIn(Iterable values) { + List terms = Optional.ofNullable(terms()).map(term -> { + List expressions = new ArrayList<>(terms()); + values.forEach(v -> expressions.add(formatter().apply(v))); + return expressions; + }).orElse(StreamSupport.stream(values.spliterator(), false).map(formatter()).collect(Collectors.toList())); + + return new ReferenceableTermFilterExpression(expression(), terms); + } + + public ReferenceableTermFilterExpression containsAny(Iterable> values) { + return isIn( + StreamSupport.stream(values.spliterator(), false).map(Identifiable::getId).collect(Collectors.toList())); + } + + public static ReferenceableTermFilterExpression of(PathExpression expression) { + return new ReferenceableTermFilterExpression(expression); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFacetExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFacetExpression.java new file mode 100644 index 00000000000..76fa833b7bf --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFacetExpression.java @@ -0,0 +1,118 @@ + +package com.commercetools.api.search.products; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class TermFacetExpression implements FacetExpression { + + private final PathExpression expression; + + private final List terms; + + private final Function formatter; + + private final boolean countingProducts; + + private final String alias; + + TermFacetExpression(final PathExpression expression, final Function formatter) { + this.expression = expression; + this.terms = null; + this.formatter = formatter; + this.alias = null; + this.countingProducts = false; + } + + TermFacetExpression(final PathExpression expression, final List terms, + final Function formatter) { + this.expression = expression; + this.terms = terms; + this.formatter = formatter; + this.alias = null; + this.countingProducts = false; + } + + TermFacetExpression(final PathExpression expression, final List terms, + final Function formatter, final String alias, final boolean countingProducts) { + this.expression = expression; + this.terms = terms; + this.formatter = formatter; + this.alias = alias; + this.countingProducts = countingProducts; + } + + PathExpression expression() { + return expression; + } + + List terms() { + return terms; + } + + Function formatter() { + return formatter; + } + + public TermFacetExpression alias(final String alias) { + return new TermFacetExpression<>(expression, terms, formatter, alias, countingProducts); + } + + public TermFacetExpression countingProducts() { + return new TermFacetExpression<>(expression, terms, formatter, alias, true); + } + + public TermFacetExpression is(final T value) { + List terms = Optional.ofNullable(terms()).map(termList -> { + List expressions = new ArrayList<>(termList); + expressions.add(formatter().apply(value)); + return expressions; + }).orElse(Collections.singletonList(formatter().apply(value))); + return new TermFacetExpression<>(expression, terms, formatter, alias, countingProducts); + } + + public TermFacetExpression isIn(final Iterable values) { + List terms = Optional.ofNullable(terms()).map(termList -> { + List expressions = new ArrayList<>(termList); + values.forEach(v -> expressions.add(formatter().apply(v))); + return expressions; + }).orElse(StreamSupport.stream(values.spliterator(), false).map(formatter()).collect(Collectors.toList())); + + return new TermFacetExpression<>(expression, terms, formatter, alias, countingProducts); + } + + public RangeFacetExpression ranges() { + return new RangeFacetExpression<>(expression, null, formatter, alias, countingProducts); + } + + public static TermFacetExpression of(final PathExpression expression, + final Function formatter) { + return new TermFacetExpression<>(expression, formatter); + } + + public static TermFacetExpression of(final PathExpression expression, final List terms, + Function formatter) { + return new TermFacetExpression<>(expression, terms, formatter); + } + + public static TermFacetExpression of(final PathExpression expression, final List terms, + final Function formatter, final String alias, final boolean countingProducts) { + return new TermFacetExpression<>(expression, terms, formatter, alias, countingProducts); + } + + @Override + public String render() { + if (terms == null || terms.isEmpty()) { + return expression.render() + renderMeta(); + } + return expression.render() + ": " + + terms.stream().map(FilterExpression::render).collect(Collectors.joining(", ")) + renderMeta(); + } + + private String renderMeta() { + return Optional.ofNullable(alias).map(s -> String.format(" as %s", alias)).orElse("") + + (countingProducts ? " counting products" : ""); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFilterExpression.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFilterExpression.java new file mode 100644 index 00000000000..9c5c96ef74a --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFilterExpression.java @@ -0,0 +1,84 @@ + +package com.commercetools.api.search.products; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class TermFilterExpression implements FilterExpression { + + private final PathExpression expression; + + private final List terms; + + private final Function formatter; + + public TermFilterExpression(PathExpression expression, Function formatter) { + this.expression = expression; + this.terms = null; + this.formatter = formatter; + } + + public TermFilterExpression(PathExpression expression, List terms, + Function formatter) { + this.expression = expression; + this.terms = terms; + this.formatter = formatter; + } + + PathExpression expression() { + return expression; + } + + List terms() { + return terms; + } + + Function formatter() { + return formatter; + } + + public TermFilterExpression is(T value) { + List terms = Optional.ofNullable(terms()).map(termList -> { + List expressions = new ArrayList<>(termList); + expressions.add(formatter().apply(value)); + return expressions; + }).orElse(Collections.singletonList(formatter().apply(value))); + return TermFilterExpression.of(expression, terms, formatter); + } + + public TermFilterExpression isIn(Iterable values) { + List terms = Optional.ofNullable(terms()).map(termList -> { + List expressions = new ArrayList<>(termList); + values.forEach(v -> expressions.add(formatter().apply(v))); + return expressions; + }).orElse(StreamSupport.stream(values.spliterator(), false).map(formatter()).collect(Collectors.toList())); + + return TermFilterExpression.of(expression, terms, formatter); + } + + public static TermFilterExpression of(PathExpression expression, Function formatter) { + return new TermFilterExpression<>(expression, formatter); + } + + public static TermFilterExpression of(PathExpression expression, List terms, + Function formatter) { + return new TermFilterExpression<>(expression, terms, formatter); + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression()).exists(); + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression()).missing(); + } + + @Override + public String render() { + Objects.requireNonNull(terms); + return expression.render() + ": " + + terms.stream().map(FilterExpression::render).collect(Collectors.joining(", ")); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFilterExpressionBuilder.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFilterExpressionBuilder.java new file mode 100644 index 00000000000..5be9d1b1ee8 --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFilterExpressionBuilder.java @@ -0,0 +1,44 @@ + +package com.commercetools.api.search.products; + +import java.util.function.Function; + +public class TermFilterExpressionBuilder { + private final PathExpression expression; + private final Function formatter; + + public TermFilterExpressionBuilder() { + this.expression = null; + this.formatter = null; + } + + public TermFilterExpressionBuilder(PathExpression expression, Function formatter) { + this.expression = expression; + this.formatter = formatter; + } + + public TermFilterExpression is(T value) { + return TermFilterExpression.of(expression, formatter).is(value); + } + + public TermFilterExpression isIn(Iterable values) { + return TermFilterExpression.of(expression, formatter).isIn(values); + } + + public FilterExpression exists() { + return new ExistsTermFilterExpression(expression).exists(); + } + + public FilterExpression missing() { + return new ExistsTermFilterExpression(expression).missing(); + } + + public RangeFilterExpression ranges() { + return new RangeFilterExpression<>(expression, null, formatter); + } + + public static TermFilterExpressionBuilder of(PathExpression expression, + Function formatter) { + return new TermFilterExpressionBuilder<>(expression, formatter); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFormatter.java b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFormatter.java new file mode 100644 index 00000000000..5db3b23c77b --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/search/products/TermFormatter.java @@ -0,0 +1,63 @@ + +package com.commercetools.api.search.products; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; + +import javax.money.CurrencyUnit; + +import com.commercetools.api.models.Identifiable; + +public class TermFormatter { + private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder().appendInstant(3).toFormatter(); + + public static ConstantExpression format(Boolean value) { + return ConstantExpression.of(String.format("%b", value)); + } + + public static ConstantExpression format(LocalDate value) { + return ConstantExpression.of(String.format("\"%s\"", value.format(DateTimeFormatter.ISO_LOCAL_DATE))); + } + + public static ConstantExpression format(ZonedDateTime value) { + return ConstantExpression + .of(String.format("\"%s\"", FORMATTER.format(value.withZoneSameInstant(ZoneOffset.UTC)))); + } + + public static ConstantExpression format(Double value) { + return ConstantExpression.of(value.toString()); + } + + public static ConstantExpression format(Long value) { + return ConstantExpression.of(String.format("%d", value)); + } + + public static ConstantExpression format(String value) { + return ConstantExpression.of(String.format("\"%s\"", escape(value))); + } + + public static ConstantExpression format(LocalTime value) { + return ConstantExpression.of(String.format("\"%s\"", value.format(DateTimeFormatter.ISO_LOCAL_TIME))); + } + + public static FilterExpression format(Identifiable value) { + return ConstantExpression.of(String.format("\"%s\"", escape(value.getId()))); + } + + public static FilterExpression format(CurrencyUnit currencyUnit) { + return ConstantExpression.of(String.format("\"%s\"", escape(currencyUnit.getCurrencyCode()))); + } + + /** + * Internal: Escapes Strings like that (Scala notation) """query by name " test name""" + * @param s the unescaped String + * @return the escaped string + */ + static String escape(final String s) { + return s.replace("\"", "\\\""); + } +} diff --git a/commercetools/commercetools-sdk-java-api/src/test/java/com/commercetools/api/search/SearchTests.java b/commercetools/commercetools-sdk-java-api/src/test/java/com/commercetools/api/search/SearchTests.java new file mode 100644 index 00000000000..af6f2742a2a --- /dev/null +++ b/commercetools/commercetools-sdk-java-api/src/test/java/com/commercetools/api/search/SearchTests.java @@ -0,0 +1,414 @@ + +package com.commercetools.api.search; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.Locale; + +import com.commercetools.api.client.ByProjectKeyProductProjectionsSearchGet; +import com.commercetools.api.client.ByProjectKeyProductProjectionsSearchPost; +import com.commercetools.api.client.ProjectApiRoot; +import com.commercetools.api.models.Identifiable; +import com.commercetools.api.models.common.DefaultCurrencyUnits; +import com.commercetools.api.search.products.*; +import com.tngtech.junit.dataprovider.DataProvider; +import com.tngtech.junit.dataprovider.DataProviderExtension; +import com.tngtech.junit.dataprovider.UseDataProvider; +import com.tngtech.junit.dataprovider.UseDataProviderExtension; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(UseDataProviderExtension.class) +@ExtendWith(DataProviderExtension.class) +public class SearchTests { + + @Test + public void getRequest() { + ByProjectKeyProductProjectionsSearchGet searchResponse = ProjectApiRoot.of("test") + .productProjections() + .search() + .get() + .filter(f -> f.categories().id().is("abc")) + .filterFacets(f -> f.categories().id().is("def")) + .filterQuery(f -> f.categories().id().is("ghi")) + .facet(f -> f.categories().id()); + + Assertions.assertThat(searchResponse.createHttpRequest().getUri().getRawQuery()) + .isEqualTo( + "filter=categories.id%3A+%22abc%22&filter.facets=categories.id%3A+%22def%22&filter.query=categories.id%3A+%22ghi%22&facet=categories.id"); + } + + @Test + public void postRequest() { + ByProjectKeyProductProjectionsSearchPost searchResponse = ProjectApiRoot.of("test") + .productProjections() + .search() + .post() + .filter(f -> f.categories().id().is("abc")) + .filterFacets(f -> f.categories().id().is("def")) + .filterQuery(f -> f.categories().id().is("ghi")) + .facet(f -> f.categories().id()); + + Assertions.assertThat(searchResponse.createHttpRequest().getSecuredBody()) + .isEqualTo( + "filter=categories.id%3A+%22abc%22&filter.facets=categories.id%3A+%22def%22&filter.query=categories.id%3A+%22ghi%22&facet=categories.id"); + } + + @TestTemplate + @UseDataProvider("filterExpressions") + public void filterRender(FilterExpression searchExpression, String expectedPredicate) { + Assertions.assertThat(searchExpression.render()).isEqualTo(expectedPredicate); + } + + @TestTemplate + @UseDataProvider("facetExpressions") + public void facetRender(FilterExpression searchExpression, String expectedPredicate) { + Assertions.assertThat(searchExpression.render()).isEqualTo(expectedPredicate); + } + + @DataProvider + public static Object[][] filterExpressions() { + return new Object[][] { new Object[] { ProductFilterExpressionBuilder.of().key().is("foo"), "key: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().key().exists(), "key: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().key().missing(), "key: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().categories().id().is("foo"), + "categories.id: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().categories().id().is("foo").is("bar"), + "categories.id: \"foo\", \"bar\"" }, + new Object[] { ProductFilterExpressionBuilder.of().categories().id().subTree("foo"), + "categories.id: subTree(\"foo\")" }, + new Object[] { ProductFilterExpressionBuilder.of().categories().id().is("foo").subTree("bar"), + "categories.id: \"foo\", subTree(\"bar\")" }, + new Object[] { ProductFilterExpressionBuilder.of().categories().id().is("foo").subTree("bar").is("baz"), + "categories.id: \"foo\", subTree(\"bar\"), \"baz\"" }, + new Object[] { ProductFilterExpressionBuilder.of().categories().exists(), "categories: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().categories().missing(), "categories: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().key().is("foo"), + "variants.key: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().key().is("foo").is("bar"), + "variants.key: \"foo\", \"bar\"" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().key().exists(), "variants.key: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().key().missing(), + "variants.key: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().sku().is("foo"), + "variants.sku: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().sku().is("foo").is("bar"), + "variants.sku: \"foo\", \"bar\"" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().sku().exists(), "variants.sku: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().sku().missing(), + "variants.sku: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().prices().exists(), + "variants.prices: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().prices().missing(), + "variants.prices: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().price().centAmount().is(100L), + "variants.price.centAmount: 100" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().price().centAmount().rangeTo(100L), + "variants.price.centAmount: range (* to 100)" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().price().centAmount().rangeFrom(100L), + "variants.price.centAmount: range (100 to *)" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().price().centAmount().range(100L, 200L), + "variants.price.centAmount: range (100 to 200)" }, + new Object[] { + ProductFilterExpressionBuilder.of() + .variants() + .price() + .centAmount() + .rangeTo(100L) + .range(100L, 200L) + .rangeFrom(200L), + "variants.price.centAmount: range (* to 100), (100 to 200), (200 to *)" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().price().currencyCode().is("EUR"), + "variants.price.currencyCode: \"EUR\"" }, + new Object[] { + ProductFilterExpressionBuilder.of().variants().price().currency().is(DefaultCurrencyUnits.EUR), + "variants.price.currencyCode: \"EUR\"" }, + new Object[] { + ProductFilterExpressionBuilder.of().variants().scopedPrice().value().centAmount().is(100L), + "variants.scopedPrice.value.centAmount: 100" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .scopedPrice() + .currentValue() + .centAmount() + .is(100L), "variants.scopedPrice.currentValue.centAmount: 100" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .scopedPrice() + .discounted() + .value() + .centAmount() + .is(100L), "variants.scopedPrice.discounted.value.centAmount: 100" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().scopedPriceDiscounted().is(true), + "variants.scopedPriceDiscounted: true" }, + new Object[] { ProductFilterExpressionBuilder.of().productType().id().is("foo"), + "productType.id: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().taxCategory().id().is("foo"), + "taxCategory.id: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().taxCategory().exists(), "taxCategory: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().taxCategory().missing(), "taxCategory: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().state().id().is("foo"), "state.id: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().state().exists(), "state: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().state().missing(), "state: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().reviewRatingStatistics().averageRating().is(100L), + "reviewRatingStatistics.averageRating: 100" }, + new Object[] { + ProductFilterExpressionBuilder.of().reviewRatingStatistics().averageRating().range(0L, 100L), + "reviewRatingStatistics.averageRating: range (0 to 100)" }, + new Object[] { ProductFilterExpressionBuilder.of().reviewRatingStatistics().lowestRating().is(100L), + "reviewRatingStatistics.lowestRating: 100" }, + new Object[] { ProductFilterExpressionBuilder.of().reviewRatingStatistics().highestRating().is(100L), + "reviewRatingStatistics.highestRating: 100" }, + new Object[] { ProductFilterExpressionBuilder.of().reviewRatingStatistics().count().is(100L), + "reviewRatingStatistics.count: 100" }, + new Object[] { + ProductFilterExpressionBuilder.of() + .createdAt() + .range(ZonedDateTime.parse("2015-06-04T12:27:55.344Z"), + ZonedDateTime.parse("2015-06-04T13:27:55.344Z")), + "createdAt: range (\"2015-06-04T12:27:55.344Z\" to \"2015-06-04T13:27:55.344Z\")" }, + new Object[] { + ProductFilterExpressionBuilder.of() + .lastModifiedAt() + .range(ZonedDateTime.parse("2015-06-04T12:27:55.344Z"), + ZonedDateTime.parse("2015-06-04T13:27:55.344Z")), + "lastModifiedAt: range (\"2015-06-04T12:27:55.344Z\" to \"2015-06-04T13:27:55.344Z\")" }, + new Object[] { ProductFilterExpressionBuilder.of().searchKeywords("en-US").is("foo"), + "searchKeywords.en-US.text: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().searchKeywords(Locale.US).is("foo"), + "searchKeywords.en-US.text: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().availability().isOnStock().is(true), + "variants.availability.isOnStock: true" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .availability() + .availableQuantity() + .range(100L, 200L), "variants.availability.availableQuantity: range (100 to 200)" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .availability() + .channel(Identifiable.of("foo")) + .isOnStock() + .is(true), "variants.availability.channels.foo.isOnStock: true" }, + new Object[] { + ProductFilterExpressionBuilder.of() + .variants() + .availability() + .channel(Identifiable.of("foo")) + .availableQuantity() + .range(100L, 200L), + "variants.availability.channels.foo.availableQuantity: range (100 to 200)" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .availability() + .channel("foo") + .isOnStock() + .is(true), "variants.availability.channels.foo.isOnStock: true" }, + new Object[] { + ProductFilterExpressionBuilder.of() + .variants() + .availability() + .channel("foo") + .availableQuantity() + .range(100L, 200L), + "variants.availability.channels.foo.availableQuantity: range (100 to 200)" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .availability() + .isOnStockInChannels() + .is("foo") + .is("bar"), "variants.availability.isOnStockInChannels: \"foo\", \"bar\"" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .availability() + .isOnStockInChannels() + .is(Identifiable.of("foo")) + .is("bar"), "variants.availability.isOnStockInChannels: \"foo\", \"bar\"" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").exists(), + "variants.attributes.foo: exists" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").missing(), + "variants.attributes.foo: missing" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").asBoolean().is(true), + "variants.attributes.foo: true" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").asLong().is(100L), + "variants.attributes.foo: 100" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").asLong().range(0L, 100L), + "variants.attributes.foo: range (0 to 100)" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").asDouble().is(100.0), + "variants.attributes.foo: 100.0" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").asDouble().is(100.0), + "variants.attributes.foo: 100.0" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").asString().is("bar"), + "variants.attributes.foo: \"bar\"" }, + new Object[] { + ProductFilterExpressionBuilder.of() + .variants() + .attribute("foo") + .asDateTime() + .is(ZonedDateTime.parse("2015-06-04T12:27:55.344Z")), + "variants.attributes.foo: \"2015-06-04T12:27:55.344Z\"" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .attribute("foo") + .asDate() + .is(LocalDate.parse("2022-03-21")), "variants.attributes.foo: \"2022-03-21\"" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .attribute("foo") + .asTime() + .is(LocalTime.parse("12:34:32")), "variants.attributes.foo: \"12:34:32\"" }, + new Object[] { + ProductFilterExpressionBuilder.of().variants().attribute("foo").asMoney().centAmount().is(100L), + "variants.attributes.foo.centAmount: 100" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .attribute("foo") + .asMoney() + .currencyCode() + .is("EUR"), "variants.attributes.foo.currencyCode: \"EUR\"" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .attribute("foo") + .asMoney() + .currency() + .is(DefaultCurrencyUnits.EUR), "variants.attributes.foo.currencyCode: \"EUR\"" }, + new Object[] { + ProductFilterExpressionBuilder.of().variants().attribute("foo").asReference().id().is("foo"), + "variants.attributes.foo.id: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of() + .variants() + .attribute("foo") + .asReference() + .typeId() + .is("foo"), "variants.attributes.foo.typeId: \"foo\"" }, + new Object[] { ProductFilterExpressionBuilder.of().variants().attribute("foo").asEnum().key().is("foo"), + "variants.attributes.foo.key: \"foo\"" }, + + }; + } + + @DataProvider + public static Object[][] facetExpressions() { + return new Object[][] { + new Object[] { ProductFacetExpressionBuilder.of().categories().id().alias("cat"), + "categories.id as cat" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id().alias("cat").countingProducts(), + "categories.id as cat counting products" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id().countingProducts().alias("cat"), + "categories.id as cat counting products" }, + new Object[] { + ProductFacetExpressionBuilder.of().categories().id().countingProducts().alias("cat").is("foo"), + "categories.id: \"foo\" as cat counting products" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id(), "categories.id" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id().is("foo"), + "categories.id: \"foo\"" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id().is("foo").is("bar"), + "categories.id: \"foo\", \"bar\"" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id().subTree("foo"), + "categories.id: subTree(\"foo\")" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id().is("foo").subTree("bar"), + "categories.id: \"foo\", subTree(\"bar\")" }, + new Object[] { ProductFacetExpressionBuilder.of().categories().id().is("foo").subTree("bar").is("baz"), + "categories.id: \"foo\", subTree(\"bar\"), \"baz\"" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofText("test-text"), + "variants.attributes.test-text" }, + new Object[] { + ProductFacetExpressionBuilder.of().variants().attribute().ofText("test-text-foo").is("foo"), + "variants.attributes.test-text-foo: \"foo\"" }, + new Object[] { + ProductFacetExpressionBuilder.of().variants().attribute().ofText("test").is("foo").is("bar"), + "variants.attributes.test: \"foo\", \"bar\"" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofDate("test-date"), + "variants.attributes.test-date" }, + new Object[] { ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofDate("test") + .is(LocalDate.parse("2024-01-03")), "variants.attributes.test: \"2024-01-03\"" }, + new Object[] { + ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofDate("test") + .is(LocalDate.parse("2024-01-03")) + .is(LocalDate.parse("2024-01-04")), + "variants.attributes.test: \"2024-01-03\", \"2024-01-04\"" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofTime("test"), + "variants.attributes.test" }, + new Object[] { ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofTime("test") + .is(LocalTime.parse("10:00")), "variants.attributes.test: \"10:00:00\"" }, + new Object[] { ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofTime("test") + .is(LocalTime.parse("10:00")) + .is(LocalTime.parse("11:00")), "variants.attributes.test: \"10:00:00\", \"11:00:00\"" }, + new Object[] { + ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofDatetime("test") + .is(ZonedDateTime.parse("2024-01-03T10:00Z")), + "variants.attributes.test: \"2024-01-03T10:00:00.000Z\"" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofEnum("test").key(), + "variants.attributes.test.key" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofEnum("test").label(), + "variants.attributes.test.label" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofEnum("test").label("en"), + "variants.attributes.test.label.en" }, + new Object[] { + ProductFacetExpressionBuilder.of().variants().attribute().ofEnum("test").label(Locale.US), + "variants.attributes.test.label.en-US" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofMoney("test").centAmount(), + "variants.attributes.test.centAmount" }, + new Object[] { + ProductFacetExpressionBuilder.of().variants().attribute().ofMoney("test").centAmount().is(100L), + "variants.attributes.test.centAmount: 100" }, + new Object[] { + ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofMoney("test") + .centAmount() + .range(0L, 100L) + .range(101L, 200L), + "variants.attributes.test.centAmount: range (0 to 100), (101 to 200)" }, + new Object[] { ProductFacetExpressionBuilder.of().variants().attribute().ofMoney("test").currencyCode(), + "variants.attributes.test.currencyCode" }, + new Object[] { ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofMoney("test") + .currencyCode() + .is("EUR"), "variants.attributes.test.currencyCode: \"EUR\"" }, + new Object[] { ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofMoney("test") + .currency() + .is(DefaultCurrencyUnits.EUR), "variants.attributes.test.currencyCode: \"EUR\"" }, + new Object[] { ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofLong("test") + .range(0L, 100L) + .rangeFrom(100L), "variants.attributes.test: range (0 to 100), (100 to *)" }, + new Object[] { + ProductFacetExpressionBuilder.of() + .variants() + .attribute() + .ofLong("test") + .range(0L, 100L) + .rangeFrom(100L) + .alias("range_test") + .countingProducts(), + "variants.attributes.test: range (0 to 100), (100 to *) as range_test counting products" }, }; + } +}