Skip to content

Commit e8e820e

Browse files
authored
Merge pull request #954 from FgForrest/953-missing-price-list-argument-you-can-use-pricelist-or-pricelists-parameter-for-specifying-custom-price-list
Missing price list argument you can use pricelist or pricelists parameter for specifying custom price list (#953)
2 parents 8765a27 + 156c1c0 commit e8e820e

File tree

13 files changed

+194
-88
lines changed

13 files changed

+194
-88
lines changed

evita_api/src/main/java/io/evitadb/api/requestResponse/EvitaRequest.java

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,70 @@ public EvitaRequest(
286286
this.requiredLocaleSet = this.locale == null ?
287287
evitaRequest.requiredLocaleSet : Set.of(this.locale);
288288
}
289-
this.queryPriceMode = evitaRequest.queryPriceMode;
290-
this.priceValidInTimeSet = evitaRequest.priceValidInTimeSet;
291-
this.priceValidInTime = evitaRequest.priceValidInTime;
289+
this.queryPriceMode = ofNullable(QueryUtils.findRequire(this.query, PriceType.class))
290+
.map(PriceType::getQueryPriceMode)
291+
.orElse(evitaRequest.queryPriceMode);
292+
if (filterBy != null) {
293+
// prefer valid in from the current filter
294+
final List<OffsetDateTime> validitySpan = QueryUtils.findConstraints(filterBy, PriceValidIn.class)
295+
.stream()
296+
.map(it -> it.getTheMoment(this::getAlignedNow))
297+
.distinct()
298+
.toList();
299+
Assert.isTrue(
300+
validitySpan.size() <= 1,
301+
"Query can not contain more than one price validity constraints!"
302+
);
303+
if (validitySpan.isEmpty()) {
304+
this.priceValidInTimeSet = evitaRequest.priceValidInTimeSet;
305+
this.priceValidInTime = evitaRequest.priceValidInTime;
306+
} else {
307+
this.priceValidInTimeSet = true;
308+
this.priceValidInTime = validitySpan.get(0);
309+
}
310+
311+
// prefer currencies from the current filter
312+
final List<Currency> currenciesFound = QueryUtils.findConstraints(filterBy, PriceInCurrency.class)
313+
.stream()
314+
.map(PriceInCurrency::getCurrency)
315+
.distinct()
316+
.toList();
317+
Assert.isTrue(
318+
currenciesFound.size() <= 1,
319+
"Query can not contain more than one currency filtering constraints!"
320+
);
321+
if (currenciesFound.isEmpty()) {
322+
this.currencySet = evitaRequest.currencySet;
323+
this.currency = evitaRequest.currency;
324+
} else {
325+
this.currency = currenciesFound.get(0);
326+
this.currencySet = true;
327+
}
328+
329+
// prefer price lists from the current filter
330+
final List<PriceInPriceLists> priceInPriceLists = QueryUtils.findConstraints(filterBy, PriceInPriceLists.class);
331+
Assert.isTrue(
332+
priceInPriceLists.size() <= 1,
333+
"Query can not contain more than one price in price lists filter constraints!"
334+
);
335+
if (priceInPriceLists.isEmpty()) {
336+
this.priceLists = evitaRequest.priceLists;
337+
this.requiresPriceLists = evitaRequest.requiresPriceLists;
338+
} else {
339+
final Optional<PriceInPriceLists> pricesInPriceList = Optional.of(priceInPriceLists.get(0));
340+
this.priceLists = pricesInPriceList
341+
.map(PriceInPriceLists::getPriceLists)
342+
.orElse(new String[0]);
343+
this.requiresPriceLists = true;
344+
}
345+
} else {
346+
this.priceValidInTimeSet = evitaRequest.priceValidInTimeSet;
347+
this.priceValidInTime = evitaRequest.priceValidInTime;
348+
this.currencySet = evitaRequest.currencySet;
349+
this.currency = evitaRequest.currency;
350+
this.priceLists = evitaRequest.priceLists;
351+
this.requiresPriceLists = evitaRequest.requiresPriceLists;
352+
}
292353
this.requiresParent = null;
293354
this.parentContent = null;
294355
this.entityAttributes = null;
@@ -299,13 +360,9 @@ public EvitaRequest(
299360
this.entityFetchRequirements = null;
300361
this.defaultReferenceRequirement = null;
301362
this.entityPrices = null;
302-
this.currencySet = evitaRequest.currencySet;
303-
this.currency = evitaRequest.currency;
304-
this.requiresPriceLists = evitaRequest.requiresPriceLists;
305-
this.additionalPriceLists = evitaRequest.additionalPriceLists;
306-
this.defaultAccompanyingPricePriceLists = evitaRequest.defaultAccompanyingPricePriceLists;
307363
this.accompanyingPrices = null;
308-
this.priceLists = evitaRequest.priceLists;
364+
this.defaultAccompanyingPricePriceLists = evitaRequest.defaultAccompanyingPricePriceLists;
365+
this.additionalPriceLists = evitaRequest.additionalPriceLists;
309366
this.start = evitaRequest.start;
310367
this.conditionalGaps = evitaRequest.conditionalGaps;
311368
this.hierarchyWithin = evitaRequest.hierarchyWithin;

evita_engine/src/main/java/io/evitadb/core/query/ReferencedEntityFetcher.java

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,16 @@
3434
import io.evitadb.api.EntityCollectionContract;
3535
import io.evitadb.api.EvitaSessionContract;
3636
import io.evitadb.api.query.FilterConstraint;
37+
import io.evitadb.api.query.OrderConstraint;
38+
import io.evitadb.api.query.filter.EntityHaving;
39+
import io.evitadb.api.query.filter.EntityLocaleEquals;
3740
import io.evitadb.api.query.filter.EntityPrimaryKeyInSet;
3841
import io.evitadb.api.query.filter.FilterBy;
3942
import io.evitadb.api.query.filter.ReferenceHaving;
43+
import io.evitadb.api.query.order.EntityPrimaryKeyExact;
44+
import io.evitadb.api.query.order.EntityPrimaryKeyInFilter;
45+
import io.evitadb.api.query.order.EntityPrimaryKeyNatural;
46+
import io.evitadb.api.query.order.EntityProperty;
4047
import io.evitadb.api.query.order.OrderBy;
4148
import io.evitadb.api.query.require.DefaultPrefetchRequirementCollector;
4249
import io.evitadb.api.query.require.EntityFetch;
@@ -45,6 +52,7 @@
4552
import io.evitadb.api.query.require.Page;
4653
import io.evitadb.api.query.require.ReferenceContent;
4754
import io.evitadb.api.query.require.Strip;
55+
import io.evitadb.api.query.visitor.FinderVisitor;
4856
import io.evitadb.api.requestResponse.EvitaRequest;
4957
import io.evitadb.api.requestResponse.EvitaRequest.RequirementContext;
5058
import io.evitadb.api.requestResponse.EvitaRequest.ResultForm;
@@ -137,6 +145,8 @@
137145

138146
import static io.evitadb.api.query.QueryConstraints.and;
139147
import static io.evitadb.api.query.QueryConstraints.entityPrimaryKeyInSet;
148+
import static io.evitadb.api.query.QueryConstraints.filterBy;
149+
import static io.evitadb.api.query.QueryConstraints.orderBy;
140150
import static io.evitadb.core.query.extraResult.translator.hierarchyStatistics.AbstractHierarchyTranslator.stopAtConstraintToPredicate;
141151
import static java.util.Optional.ofNullable;
142152

@@ -230,7 +240,12 @@ private static Map<Integer, ServerEntityDecorator> fetchReferencedEntities(
230240
return Collections.emptyMap();
231241
} else {
232242
// finally, create the fetch request, get the collection and fetch the referenced entity bodies
233-
final EvitaRequest fetchRequest = executionContext.getEvitaRequest().deriveCopyWith(entityType, entityFilterBy, entityOrderBy, entityFetch);
243+
final EvitaRequest fetchRequest = executionContext.getEvitaRequest().deriveCopyWith(
244+
entityType,
245+
unwrapFilterBy(entityFilterBy),
246+
unwrapOrderBy(entityOrderBy),
247+
entityFetch
248+
);
234249
final EntityCollection referencedCollection = executionContext.getEntityCollectionOrThrowException(
235250
entityType, "fetch references"
236251
);
@@ -241,6 +256,69 @@ private static Map<Integer, ServerEntityDecorator> fetchReferencedEntities(
241256
}
242257
}
243258

259+
/**
260+
* Unwraps the provided {@code entityFilterBy} object to extract its nested filter criteria.
261+
* If the {@code entityFilterBy} contains an {@code EntityHaving} constraint,
262+
* the method creates a new {@code FilterBy} instance with the child constraints of {@code EntityHaving}.
263+
* If no {@code EntityHaving} constraint is found or {@code entityFilterBy} is null, the method returns null.
264+
*
265+
* @param entityFilterBy the {@code FilterBy} object potentially containing an {@code EntityHaving} constraint
266+
* @return a new {@code FilterBy} instance with the child constraints of {@code EntityHaving},
267+
* or null if the {@code entityFilterBy} is null or does not contain an {@code EntityHaving} constraint
268+
*/
269+
@Nullable
270+
private static FilterBy unwrapFilterBy(@Nullable FilterBy entityFilterBy) {
271+
final FilterBy unwrappedEntityFilterBy;
272+
if (entityFilterBy != null) {
273+
final List<FilterConstraint> entityConstraints = FinderVisitor.findConstraints(
274+
entityFilterBy,
275+
it -> it instanceof EntityHaving || it instanceof EntityPrimaryKeyInSet || it instanceof EntityLocaleEquals,
276+
EntityHaving.class::isInstance
277+
);
278+
unwrappedEntityFilterBy = filterBy(
279+
entityConstraints
280+
.stream()
281+
.flatMap(it -> it instanceof EntityHaving eh ? Arrays.stream(eh.getChildren()) : Stream.of(it))
282+
.toArray(FilterConstraint[]::new)
283+
);
284+
} else {
285+
unwrappedEntityFilterBy = null;
286+
}
287+
return unwrappedEntityFilterBy;
288+
}
289+
290+
/**
291+
* Unwraps the provided {@code OrderBy} object by extracting its relevant constraints and
292+
* constructing a new {@code OrderBy} instance based on its children.
293+
*
294+
* @param entityOrderBy the {@code OrderBy} object to be unwrapped; may be null
295+
* @return a new {@code OrderBy} instance derived from the provided {@code OrderBy},
296+
* or null if the input is null or its constraints do not meet the expected criteria
297+
*/
298+
@Nullable
299+
private static OrderBy unwrapOrderBy(@Nullable OrderBy entityOrderBy) {
300+
final OrderBy unwrappedEntityFilterBy;
301+
if (entityOrderBy != null) {
302+
final List<OrderConstraint> entityConstraints = FinderVisitor.findConstraints(
303+
entityOrderBy,
304+
it -> it instanceof EntityProperty ||
305+
it instanceof EntityPrimaryKeyExact ||
306+
it instanceof EntityPrimaryKeyNatural ||
307+
it instanceof EntityPrimaryKeyInFilter,
308+
EntityProperty.class::isInstance
309+
);
310+
unwrappedEntityFilterBy = orderBy(
311+
entityConstraints
312+
.stream()
313+
.flatMap(it -> it instanceof EntityProperty eh ? Arrays.stream(eh.getChildren()) : Stream.of(it))
314+
.toArray(OrderConstraint[]::new)
315+
);
316+
} else {
317+
unwrappedEntityFilterBy = null;
318+
}
319+
return unwrappedEntityFilterBy;
320+
}
321+
244322
/**
245323
* Method fetches all `referencedRecordIds` from the `referencedCollection`.
246324
*

evita_engine/src/main/java/module-info.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@
9999

100100
requires jdk.jfr;
101101
requires net.bytebuddy;
102-
requires java.sql;
103-
requires jdk.jdi;
104102
requires proxycian.bytebuddy;
105103

106104
opens io.evitadb.core.metric.event to evita.common;

evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/resolver/dataFetcher/EntityQueryContext.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* | __/\ V /| | || (_| | |_| | |_) |
77
* \___| \_/ |_|\__\__,_|____/|____/
88
*
9-
* Copyright (c) 2023
9+
* Copyright (c) 2023-2025
1010
*
1111
* Licensed under the Business Source License, Version 1.1 (the "License");
1212
* you may not use this file except in compliance with the License.
@@ -30,8 +30,6 @@
3030

3131
import javax.annotation.Nonnull;
3232
import javax.annotation.Nullable;
33-
import java.time.OffsetDateTime;
34-
import java.util.Currency;
3533
import java.util.Locale;
3634

3735
/**
@@ -49,17 +47,10 @@
4947
@RequiredArgsConstructor
5048
public final class EntityQueryContext {
5149

52-
private static final EntityQueryContext EMPTY = new EntityQueryContext(null, null, null, null, false);
50+
private static final EntityQueryContext EMPTY = new EntityQueryContext(null);
5351

5452
@Nullable
5553
private final Locale desiredLocale;
56-
@Nullable
57-
private final Currency desiredPriceInCurrency;
58-
@Nullable
59-
private final String[] desiredPriceInPriceLists;
60-
@Nullable
61-
private final OffsetDateTime desiredPriceValidIn;
62-
private final boolean desiredPriceValidInNow;
6354

6455
@Nonnull
6556
public static EntityQueryContext empty() {

evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/resolver/dataFetcher/GetEntityDataFetcher.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* | __/\ V /| | || (_| | |_| | |_) |
77
* \___| \_/ |_|\__\__,_|____/|____/
88
*
9-
* Copyright (c) 2023-2024
9+
* Copyright (c) 2023-2025
1010
*
1111
* Licensed under the Business Source License, Version 1.1 (the "License");
1212
* you may not use this file except in compliance with the License.
@@ -221,11 +221,7 @@ private Require buildRequire(@Nonnull DataFetchingEnvironment environment, @Nonn
221221
@Nonnull
222222
private static EntityQueryContext buildResultContext(@Nonnull Arguments arguments) {
223223
return new EntityQueryContext(
224-
arguments.locale(),
225-
arguments.priceInCurrency(),
226-
arguments.priceInPriceLists(),
227-
arguments.priceValidIn(),
228-
arguments.priceValidInNow()
224+
arguments.locale()
229225
);
230226
}
231227

evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/resolver/dataFetcher/GetUnknownEntityDataFetcher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ private Optional<EntityContentRequire[]> buildEnrichingRequires(@Nonnull DataFet
288288

289289
@Nonnull
290290
private static EntityQueryContext buildResultContext(@Nonnull Arguments arguments) {
291-
return new EntityQueryContext(arguments.locale(), null, null, null, false);
291+
return new EntityQueryContext(arguments.locale());
292292
}
293293

294294
/**

evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/resolver/dataFetcher/ListEntitiesDataFetcher.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,7 @@ private static EntityQueryContext buildResultContext(@Nonnull Query query) {
259259
.orElse(null);
260260

261261
return new EntityQueryContext(
262-
desiredLocale,
263-
desiredPriceInCurrency,
264-
desiredPriceInPriceLists,
265-
desiredPriceValidIn == OffsetDateTime.MIN ? null : desiredPriceValidIn,
266-
desiredPriceValidIn == OffsetDateTime.MIN
262+
desiredLocale
267263
);
268264
}
269265

evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/resolver/dataFetcher/ListUnknownEntitiesDataFetcher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ private Optional<EntityContentRequire[]> buildEnrichingRequires(@Nonnull DataFet
310310

311311
@Nonnull
312312
private static EntityQueryContext buildResultContext(@Nonnull Arguments arguments) {
313-
return new EntityQueryContext(arguments.locale(), null, null, null, false);
313+
return new EntityQueryContext(arguments.locale());
314314
}
315315

316316
/**

evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/resolver/dataFetcher/QueryEntitiesDataFetcher.java

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -338,25 +338,8 @@ private static EntityQueryContext buildResultContext(@Nonnull Query query) {
338338
.map(EntityLocaleEquals::getLocale)
339339
.orElse(null);
340340

341-
final Currency desiredPriceInCurrency = Optional.ofNullable(QueryUtils.findFilter(query, PriceInCurrency.class))
342-
.map(PriceInCurrency::getCurrency)
343-
.orElse(null);
344-
345-
final Optional<PriceValidIn> priceValidInConstraint = Optional.ofNullable(QueryUtils.findFilter(query, PriceValidIn.class));
346-
final OffsetDateTime desiredPriceValidIn = priceValidInConstraint
347-
.map(it -> it.getTheMoment(() -> OffsetDateTime.MIN))
348-
.orElse(null);
349-
350-
final String[] desiredPriceInPriceLists = Optional.ofNullable(QueryUtils.findFilter(query, PriceInPriceLists.class))
351-
.map(PriceInPriceLists::getPriceLists)
352-
.orElse(null);
353-
354341
return new EntityQueryContext(
355-
desiredLocale,
356-
desiredPriceInCurrency,
357-
desiredPriceInPriceLists,
358-
desiredPriceValidIn == OffsetDateTime.MIN ? null : desiredPriceValidIn,
359-
desiredPriceValidIn == OffsetDateTime.MIN
342+
desiredLocale
360343
);
361344
}
362345

0 commit comments

Comments
 (0)