diff --git a/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicate.java b/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicate.java index fe3bc31ec..7d2e4c57c 100644 --- a/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicate.java +++ b/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicate.java @@ -51,6 +51,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.util.Optional.ofNullable; + /** * This predicate allows limiting number of references visible to the client based on query constraints. * @@ -64,6 +66,10 @@ public class ReferenceContractSerializablePredicate implements SerializablePredi * Contains information about all reference names that has been fetched / requested for the entity. */ @Nonnull @Getter private final Map referenceSet; + /** + * Contains information about default attribute request for references that has no explicit attribute request. + */ + @Nullable @Getter private final AttributeRequest defaultAttributeRequest; /** * Contains true if any of the references of the entity has been fetched / requested. */ @@ -88,6 +94,7 @@ public class ReferenceContractSerializablePredicate implements SerializablePredi public ReferenceContractSerializablePredicate() { this.requiresEntityReferences = true; this.referenceSet = Collections.emptyMap(); + this.defaultAttributeRequest = null; this.implicitLocale = null; this.locales = Collections.emptySet(); this.underlyingPredicate = null; @@ -104,6 +111,9 @@ public ReferenceContractSerializablePredicate(@Nonnull EvitaRequest evitaRequest entry -> entry.getValue().attributeRequest() ) ); + this.defaultAttributeRequest = ofNullable(evitaRequest.getDefaultReferenceRequirement()) + .map(RequirementContext::attributeRequest) + .orElse(null); this.implicitLocale = evitaRequest.getImplicitLocale(); this.locales = evitaRequest.getRequiredLocales(); this.underlyingPredicate = null; @@ -112,6 +122,7 @@ public ReferenceContractSerializablePredicate(@Nonnull EvitaRequest evitaRequest public ReferenceContractSerializablePredicate(boolean requiresEntityReferences) { this.requiresEntityReferences = requiresEntityReferences; this.referenceSet = Collections.emptyMap(); + this.defaultAttributeRequest = null; this.implicitLocale = null; this.locales = Collections.emptySet(); this.underlyingPredicate = null; @@ -137,6 +148,9 @@ public ReferenceContractSerializablePredicate( entry -> entry.getValue().attributeRequest() ) ); + this.defaultAttributeRequest = ofNullable(evitaRequest.getDefaultReferenceRequirement()) + .map(RequirementContext::attributeRequest) + .orElse(null); this.implicitLocale = evitaRequest.getImplicitLocale(); this.locales = evitaRequest.getRequiredLocales(); this.underlyingPredicate = underlyingPredicate; @@ -144,11 +158,13 @@ public ReferenceContractSerializablePredicate( ReferenceContractSerializablePredicate( @Nonnull Map referenceSet, + @Nullable AttributeRequest defaultAttributeRequest, boolean requiresEntityReferences, @Nullable Locale implicitLocale, @Nonnull Set locales ) { this.referenceSet = referenceSet; + this.defaultAttributeRequest = defaultAttributeRequest; this.requiresEntityReferences = requiresEntityReferences; this.implicitLocale = implicitLocale; this.locales = locales; @@ -209,9 +225,13 @@ public ReferenceContractSerializablePredicate createRicherCopyWith(@Nonnull Evit final Map requiredReferencedEntities = combineReferencedEntities(evitaRequest); final boolean doesRequireEntityReferences = evitaRequest.isRequiresEntityReferences(); + final AttributeRequest defaultAttributeRequest = ofNullable(evitaRequest.getDefaultReferenceRequirement()) + .map(RequirementContext::attributeRequest) + .orElse(null); if ((this.requiresEntityReferences || !doesRequireEntityReferences) && Objects.equals(this.referenceSet, requiredReferencedEntities) && + Objects.equals(this.defaultAttributeRequest, defaultAttributeRequest) && Objects.equals(this.implicitLocale, evitaRequest.getImplicitLocale()) && Objects.equals(this.locales, requiredLocales) ) { @@ -219,6 +239,7 @@ public ReferenceContractSerializablePredicate createRicherCopyWith(@Nonnull Evit } else { return new ReferenceContractSerializablePredicate( requiredReferencedEntities, + mergeAttributeRequests(this.defaultAttributeRequest, defaultAttributeRequest), this.requiresEntityReferences || doesRequireEntityReferences, implicitLocale, requiredLocales @@ -232,11 +253,25 @@ public ReferenceAttributeValueSerializablePredicate getAttributePredicate(@Nonnu this.implicitLocale, this.locales, this.referenceSet.isEmpty() ? - AttributeRequest.FULL : + (this.defaultAttributeRequest == null ? AttributeRequest.EMPTY : this.defaultAttributeRequest) : this.referenceSet.getOrDefault(referenceName, AttributeRequest.EMPTY) ); } + @Nullable + public Set getAllLocales() { + if (this.implicitLocale != null && this.locales == null) { + return Set.of(this.implicitLocale); + } else if (this.implicitLocale != null) { + return Stream.concat( + Stream.of(implicitLocale), + locales.stream() + ).collect(Collectors.toSet()); + } else { + return this.locales; + } + } + @Nonnull private Map combineReferencedEntities(@Nonnull EvitaRequest evitaRequest) { final Map requiredReferences; @@ -257,26 +292,8 @@ private Map combineReferencedEntities(@Nonnull EvitaRe for (Entry newEntry : referenceEntityFetch.entrySet()) { final AttributeRequest existingAttributeRequest = requiredReferences.get(newEntry.getKey()); final AttributeRequest newAttributeRequest = newEntry.getValue().attributeRequest(); - if (existingAttributeRequest == null) { - requiredReferences.put(newEntry.getKey(), newAttributeRequest); - } else { - final AttributeRequest attributeRequest; - if (existingAttributeRequest.isRequiresEntityAttributes() && existingAttributeRequest.attributeSet().isEmpty()) { - attributeRequest = existingAttributeRequest; - } else if (newAttributeRequest.isRequiresEntityAttributes() && newAttributeRequest.attributeSet().isEmpty()) { - attributeRequest = newAttributeRequest; - } else { - attributeRequest = new AttributeRequest( - CollectionUtils.combine(existingAttributeRequest.attributeSet(), newAttributeRequest.attributeSet()), - existingAttributeRequest.isRequiresEntityAttributes() || - newAttributeRequest.isRequiresEntityAttributes() - ); - } - requiredReferences.put( - newEntry.getKey(), - attributeRequest - ); - } + final AttributeRequest mergedAttributeRequest = mergeAttributeRequests(existingAttributeRequest, newAttributeRequest); + requiredReferences.put(newEntry.getKey(), mergedAttributeRequest); } } else { requiredReferences = this.referenceSet; @@ -284,18 +301,29 @@ private Map combineReferencedEntities(@Nonnull EvitaRe return requiredReferences; } - @Nullable - public Set getAllLocales() { - if (this.implicitLocale != null && this.locales == null) { - return Set.of(this.implicitLocale); - } else if (this.implicitLocale != null) { - return Stream.concat( - Stream.of(implicitLocale), - locales.stream() - ).collect(Collectors.toSet()); + private static AttributeRequest mergeAttributeRequests( + @Nullable AttributeRequest existingAttributeRequest, + @Nullable AttributeRequest newAttributeRequest + ) { + final AttributeRequest mergedAttributeRequest; + if (existingAttributeRequest == null) { + mergedAttributeRequest = newAttributeRequest; } else { - return this.locales; + final AttributeRequest attributeRequest; + if (existingAttributeRequest.isRequiresEntityAttributes() && existingAttributeRequest.attributeSet().isEmpty()) { + attributeRequest = existingAttributeRequest; + } else if (newAttributeRequest.isRequiresEntityAttributes() && newAttributeRequest.attributeSet().isEmpty()) { + attributeRequest = newAttributeRequest; + } else { + attributeRequest = new AttributeRequest( + CollectionUtils.combine(existingAttributeRequest.attributeSet(), newAttributeRequest.attributeSet()), + existingAttributeRequest.isRequiresEntityAttributes() || + newAttributeRequest.isRequiresEntityAttributes() + ); + } + mergedAttributeRequest = attributeRequest; } + return mergedAttributeRequest; } @Nullable diff --git a/evita_engine/src/main/java/io/evitadb/core/query/QueryContext.java b/evita_engine/src/main/java/io/evitadb/core/query/QueryContext.java index 81b754874..3df17e658 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/QueryContext.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/QueryContext.java @@ -503,6 +503,18 @@ public int translateEntity(@Nonnull EntityContract entity) { } } + /** + * Method returns requested entity primary key by specifying its primary key (either virtual or real). + */ + public int translateToEntityPrimaryKey(int primaryKey) { + if (this.entityReferencePkSequence > 0) { + final EntityReferenceContract referencedEntity = this.entityReferencePkIndex.get(primaryKey); + return referencedEntity == null ? primaryKey : referencedEntity.getPrimaryKey(); + } else { + return primaryKey; + } + } + /** * Method returns requested {@link EntityReference} by specifying its primary key (either virtual or real). */ diff --git a/evita_engine/src/main/java/io/evitadb/core/query/QueryPlanner.java b/evita_engine/src/main/java/io/evitadb/core/query/QueryPlanner.java index a06c44c04..bf7b3f5f7 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/QueryPlanner.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/QueryPlanner.java @@ -49,8 +49,10 @@ import io.evitadb.core.query.indexSelection.TargetIndexes; import io.evitadb.core.query.sort.CacheableSorter; import io.evitadb.core.query.sort.ConditionalSorter; +import io.evitadb.core.query.sort.NoSorter; import io.evitadb.core.query.sort.OrderByVisitor; import io.evitadb.core.query.sort.Sorter; +import io.evitadb.core.query.sort.primaryKey.TranslatedPrimaryKeySorter; import io.evitadb.index.CatalogIndex; import io.evitadb.index.EntityIndex; import io.evitadb.index.EntityIndexType; @@ -433,7 +435,7 @@ private static List createSorter( // in case of debug cached variant tree or the entity is not known, we cannot use cache here // and we need to retain original non-cached sorter final Sorter sorter = orderByVisitor.getSorter(); - builder.appendSorter(sorter); + builder.appendSorter(replaceNoSorterIfNecessary(queryContext, sorter)); } finally { if (multipleAlternatives) { queryContext.popStep(); @@ -456,7 +458,7 @@ private static List createSorter( queryContext, builder.getFilterFormula(), builder.getTargetIndexes(), builder.getPrefetchFormulaVisitor(), - replacedSorter + replaceNoSorterIfNecessary(queryContext, replacedSorter) ) ); } else { @@ -472,6 +474,26 @@ private static List createSorter( } } + /** + * This method replaces no sorter - which should always represent primary keys in ascending order - with the special + * implementation in case the entity is not known in the query. In such case the primary keys are translated + * different ids and those ids are translated back at the end of the query. Unfortunately the order of the translated + * keys might be different than the original order of the primary keys, so we need to sort them here according to + * their original primary keys order in ascending fashion. + * + * @param queryContext query context + * @param sorter identified sorter + * @return sorter in input or new implementation that ensures proper sorting by primary keys in ascending order + */ + @Nonnull + private static Sorter replaceNoSorterIfNecessary(@Nonnull QueryContext queryContext, @Nonnull Sorter sorter) { + if (sorter instanceof NoSorter && !queryContext.isEntityTypeKnown()) { + return TranslatedPrimaryKeySorter.INSTANCE; + } else { + return sorter; + } + } + /** * Method creates list of {@link ExtraResultProducer} implementations that fabricate requested extra data structures * that are somehow connected with the processed query taking existing formula and their memoized results into diff --git a/evita_engine/src/main/java/io/evitadb/core/query/sort/primaryKey/ReversedSorter.java b/evita_engine/src/main/java/io/evitadb/core/query/sort/primaryKey/ReversedSorter.java index a7394e635..047a5f115 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/sort/primaryKey/ReversedSorter.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/sort/primaryKey/ReversedSorter.java @@ -73,8 +73,9 @@ public int sortAndSlice(@Nonnull QueryContext queryContext, @Nonnull Formula inp // copy the sorted data to result final int length = endIndex - startIndex; - System.arraycopy(filteredRecordIds, startIndex, result, peak, Math.min(result.length, length)); - return length; + final int newPeak = Math.min(filteredRecordIds.length, length); + System.arraycopy(filteredRecordIds, startIndex, result, peak, newPeak); + return newPeak; } } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/sort/primaryKey/TranslatedPrimaryKeySorter.java b/evita_engine/src/main/java/io/evitadb/core/query/sort/primaryKey/TranslatedPrimaryKeySorter.java new file mode 100644 index 000000000..70fdb2cca --- /dev/null +++ b/evita_engine/src/main/java/io/evitadb/core/query/sort/primaryKey/TranslatedPrimaryKeySorter.java @@ -0,0 +1,87 @@ +/* + * + * _ _ ____ ____ + * _____ _(_) |_ __ _| _ \| __ ) + * / _ \ \ / / | __/ _` | | | | _ \ + * | __/\ V /| | || (_| | |_| | |_) | + * \___| \_/ |_|\__\__,_|____/|____/ + * + * Copyright (c) 2023 + * + * Licensed under the Business Source License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/FgForrest/evitaDB/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.evitadb.core.query.sort.primaryKey; + +import io.evitadb.core.query.QueryContext; +import io.evitadb.core.query.algebra.Formula; +import io.evitadb.core.query.sort.Sorter; +import io.evitadb.index.bitmap.Bitmap; +import io.evitadb.utils.ArrayUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * This sorter sorts translated primary keys according to original primary keys in ascending order. It is used with + * the special implementation in case the entity is not known in the query. In such case the primary keys are translated + * different ids and those ids are translated back at the end of the query. Unfortunately the order of the translated + * keys might be different than the original order of the primary keys, so we need to sort them here according to + * their original primary keys order in ascending fashion. + * + * @author Jan Novotný (novotny@fg.cz), FG Forrest a.s. (c) 2023 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TranslatedPrimaryKeySorter implements Sorter { + public static final Sorter INSTANCE = new TranslatedPrimaryKeySorter(); + + @Nonnull + @Override + public Sorter cloneInstance() { + return INSTANCE; + } + + @Nonnull + @Override + public Sorter andThen(Sorter sorterForUnknownRecords) { + return INSTANCE; + } + + @Nullable + @Override + public Sorter getNextSorter() { + return null; + } + + @Override + public int sortAndSlice(@Nonnull QueryContext queryContext, @Nonnull Formula input, int startIndex, int endIndex, @Nonnull int[] result, int peak) { + final Bitmap translatedPrimaryKeysBitmap = input.compute(); + final int[] translatedPrimaryKeys = translatedPrimaryKeysBitmap.getArray(); + final int[] originalPrimaryKeys = translatedPrimaryKeysBitmap.stream().map(queryContext::translateToEntityPrimaryKey).toArray(); + // initialize order array + final int[] order = new int[originalPrimaryKeys.length]; + for (int i = 0; i < order.length; i++) { + order[i] = i; + } + + ArrayUtils.sortSecondAlongFirstArray(originalPrimaryKeys, order); + final int length = endIndex - startIndex; + for (int i = peak; i < translatedPrimaryKeys.length && i < length; i++) { + result[i] = translatedPrimaryKeys[order[i]]; + } + return peak + Math.min(translatedPrimaryKeys.length, length); + } + +} diff --git a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/catalog/dataApi/resolver/endpoint/ListUnknownEntitiesHandler.java b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/catalog/dataApi/resolver/endpoint/ListUnknownEntitiesHandler.java index 372e526d7..29188679c 100644 --- a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/catalog/dataApi/resolver/endpoint/ListUnknownEntitiesHandler.java +++ b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/catalog/dataApi/resolver/endpoint/ListUnknownEntitiesHandler.java @@ -41,7 +41,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; /** * Handles requests for multiple unknown entities identified by their URLs or codes. @@ -72,8 +71,6 @@ protected EndpointResponse> doHandleRequest(@Nonnull Rest log.debug("Generated evitaDB query for unknown entity list fetch is `{}`.", query); final List entities = exchange.session().queryList(query, EntityClassifier.class); - log.info("Fetched list of unknown entities: {}", entities.stream().map(it -> it.getPrimaryKey().toString()).collect(Collectors.joining(", "))); - return new SuccessEndpointResponse<>(entities); } diff --git a/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java b/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java index 10fa24aed..fd490d441 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java @@ -538,7 +538,7 @@ DataCarrier setUp(Evita evita) { tuple( "originalProductEntities", storedProducts.stream() - .map(it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAll(), dataInLocalesAll()).orElse(null)) + .map(it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAllWithAttributes(), dataInLocalesAll()).orElse(null)) .collect(toList()) ), tuple( @@ -547,7 +547,7 @@ DataCarrier setUp(Evita evita) { .collect( toMap( EntityReference::getPrimaryKey, - it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAll(), dataInLocalesAll()).orElse(null) + it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAllWithAttributes(), dataInLocalesAll()).orElse(null) ) ) ), @@ -557,7 +557,7 @@ DataCarrier setUp(Evita evita) { .collect( toMap( EntityReference::getPrimaryKey, - it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAll(), dataInLocalesAll()).orElse(null) + it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAllWithAttributes(), dataInLocalesAll()).orElse(null) ) ) ), diff --git a/evita_functional_tests/src/test/java/io/evitadb/api/EntityFetchingFunctionalTest.java b/evita_functional_tests/src/test/java/io/evitadb/api/EntityFetchingFunctionalTest.java index d7609428c..264b5b08c 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/api/EntityFetchingFunctionalTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/api/EntityFetchingFunctionalTest.java @@ -28,6 +28,7 @@ import io.evitadb.api.query.order.OrderDirection; import io.evitadb.api.query.require.PriceContentMode; import io.evitadb.api.requestResponse.EvitaResponse; +import io.evitadb.api.requestResponse.data.AttributesAvailabilityChecker; import io.evitadb.api.requestResponse.data.AttributesContract; import io.evitadb.api.requestResponse.data.EntityClassifierWithParent; import io.evitadb.api.requestResponse.data.EntityContract; @@ -1373,6 +1374,90 @@ void shouldRetrieveMultipleEntitiesWithSpecificReferencesByPrimaryKey(Evita evit ); } + @DisplayName("Entities should be found by their primary keys with all references without attributes") + @UseDataSet(HUNDRED_PRODUCTS) + @Test + void shouldRetrieveEntitiesWithoutReferenceAttributes(Evita evita, List originalProducts) { + final Integer[] entitiesMatchingTheRequirements = getRequestedIdsByPredicate( + originalProducts, + it -> it.getReferences().stream().noneMatch(ref -> ref.getAttributeValues().isEmpty()) + ); + + evita.queryCatalog( + TEST_CATALOG, + session -> { + final EvitaResponse productByPk = session.querySealedEntity( + query( + collection(Entities.PRODUCT), + filterBy( + entityPrimaryKeyInSet(entitiesMatchingTheRequirements) + ), + require( + entityFetch( + referenceContentAll() + ), + page(1, 4) + ) + ) + ); + + assertEquals(4, productByPk.getRecordData().size()); + assertEquals(entitiesMatchingTheRequirements.length, productByPk.getTotalRecordCount()); + + for (SealedEntity product : productByPk.getRecordData()) { + assertTrue( + product.getReferences() + .stream() + .noneMatch(AttributesAvailabilityChecker::attributesAvailable) + ); + } + return null; + } + ); + } + + @DisplayName("Entities should be found by their primary keys with all references with all attributes") + @UseDataSet(HUNDRED_PRODUCTS) + @Test + void shouldRetrieveEntitiesWithAllReferenceAttributes(Evita evita, List originalProducts) { + final Integer[] entitiesMatchingTheRequirements = getRequestedIdsByPredicate( + originalProducts, + it -> it.getReferences().stream().noneMatch(ref -> ref.getAttributeValues().isEmpty()) + ); + + evita.queryCatalog( + TEST_CATALOG, + session -> { + final EvitaResponse productByPk = session.querySealedEntity( + query( + collection(Entities.PRODUCT), + filterBy( + entityPrimaryKeyInSet(entitiesMatchingTheRequirements) + ), + require( + entityFetch( + referenceContentAllWithAttributes() + ), + page(1, 4) + ) + ) + ); + + assertEquals(4, productByPk.getRecordData().size()); + assertEquals(entitiesMatchingTheRequirements.length, productByPk.getTotalRecordCount()); + + for (SealedEntity product : productByPk.getRecordData()) { + assertTrue( + product.getReferences() + .stream() + .allMatch(AttributesAvailabilityChecker::attributesAvailable) + ); + } + return null; + } + ); + } + @DisplayName("Multiple entities with specific references with exactly stated attributes can be retrieved") @UseDataSet(HUNDRED_PRODUCTS) @Test diff --git a/evita_functional_tests/src/test/java/io/evitadb/api/ReferencingEntityByHierarchyFilteringFunctionalTest.java b/evita_functional_tests/src/test/java/io/evitadb/api/ReferencingEntityByHierarchyFilteringFunctionalTest.java index 9a0cef705..37db9696c 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/api/ReferencingEntityByHierarchyFilteringFunctionalTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/api/ReferencingEntityByHierarchyFilteringFunctionalTest.java @@ -190,7 +190,7 @@ DataCarrier setUp(Evita evita) { tuple( "originalProductEntities", storedProducts.stream() - .map(it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAll(), dataInLocalesAll()).orElseThrow()) + .map(it -> session.getEntity(it.getType(), it.getPrimaryKey(), attributeContentAll(), referenceContentAllWithAttributes(), dataInLocalesAll()).orElseThrow()) .collect(Collectors.toList()) ), tuple( diff --git a/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicateTest.java b/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicateTest.java index 3e78290b9..30ef7fe3a 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicateTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/data/structure/predicate/ReferenceContractSerializablePredicateTest.java @@ -93,6 +93,7 @@ private static RequirementContext createRequirementContext(String... attributes) void shouldCreateRicherCopyForNoReferences() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, false, null, Collections.emptySet() @@ -110,6 +111,7 @@ void shouldCreateRicherCopyForNoReferences() { void shouldNotCreateRicherCopyForNoReferences() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, true, null, Collections.emptySet() @@ -127,6 +129,7 @@ void shouldNotCreateRicherCopyForNoReferences() { void shouldNotCreateRicherCopyForNoReferencesWhenReferencesPresent() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, true, null, Collections.emptySet() @@ -144,6 +147,7 @@ void shouldNotCreateRicherCopyForNoReferencesWhenReferencesPresent() { void shouldCreateRicherCopyForReferences() { final ReferenceContractSerializablePredicate referencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, true, null, Collections.emptySet() @@ -161,6 +165,7 @@ void shouldCreateRicherCopyForReferences() { void shouldNotCreateRicherCopyForReferences() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( toAttributeRequestIndex(getDefaultRequirementContext()), + null, true, null, Collections.emptySet() @@ -180,6 +185,7 @@ void shouldNotCreateRicherCopyForReferencesSubset() { toAttributeRequestIndex( getDefaultRequirementContext(Arrays.asList("A", "B")) ), + null, true, null, Collections.emptySet() @@ -197,6 +203,7 @@ void shouldNotCreateRicherCopyForReferencesSubset() { void shouldCreateRicherCopyForRicherCopyOfAttributePredicate() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, true, null, Collections.emptySet() @@ -217,6 +224,7 @@ void shouldCreateRicherCopyForRicherCopyOfAttributePredicate() { void shouldCreateRicherCopyForGlobalAndLocalizedAttributes() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, true, null, new HashSet<>(Collections.singletonList(Locale.ENGLISH)) @@ -237,6 +245,7 @@ void shouldCreateRicherCopyForGlobalAndLocalizedAttributes() { void shouldNotCreateRicherCopyForGlobalAndLocalizedAttributes() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, true, null, new HashSet<>(Arrays.asList(Locale.ENGLISH, Locale.CANADA)) @@ -256,6 +265,7 @@ void shouldNotCreateRicherCopyForGlobalAndLocalizedAttributes() { void shouldNotCreateRicherCopyForGlobalAndLocalizedAttributesSubset() { final ReferenceContractSerializablePredicate noReferencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, true, null, new HashSet<>(Arrays.asList(Locale.ENGLISH, Locale.CANADA)) @@ -275,6 +285,7 @@ void shouldNotCreateRicherCopyForGlobalAndLocalizedAttributesSubset() { void shouldCreateRicherCopyForAttributesByName() { final ReferenceContractSerializablePredicate referencesRequired = new ReferenceContractSerializablePredicate( Collections.emptyMap(), + null, false, null, new HashSet<>(Collections.singletonList(Locale.ENGLISH)) @@ -301,6 +312,7 @@ void shouldCreateRicherCopyForAttributesByNameWithDefinedBasis() { Map.of( "A", createRequirementContext("D", "E").attributeRequest() ), + null, true, null, new HashSet<>(Collections.singletonList(Locale.ENGLISH)) @@ -327,6 +339,7 @@ void shouldCreateRicherCopyForAttributesByNameWithDefinedBasisAndOverriddenByAll Map.of( "A", createRequirementContext("D", "E").attributeRequest() ), + null, true, null, new HashSet<>(Collections.singletonList(Locale.ENGLISH)) @@ -354,6 +367,7 @@ void shouldCreateRicherCopyForAttributesByNameWithAllBasisAndOverriddenByAFew() Map.of( "A", createRequirementContext().attributeRequest() ), + null, true, null, new HashSet<>(Collections.singletonList(Locale.ENGLISH)) diff --git a/evita_functional_tests/src/test/java/io/evitadb/core/EvitaIndexingTest.java b/evita_functional_tests/src/test/java/io/evitadb/core/EvitaIndexingTest.java index 57dd0d314..93994a7be 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/core/EvitaIndexingTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/core/EvitaIndexingTest.java @@ -881,7 +881,7 @@ void shouldAcceptNullInNonNullableAttributeWhenDefaultValueIsSet() { evita.queryCatalog( TEST_CATALOG, session -> { - final SealedEntity product = session.getEntity(Entities.PRODUCT, 1, attributeContent(), dataInLocalesAll(), referenceContentAll()) + final SealedEntity product = session.getEntity(Entities.PRODUCT, 1, attributeContent(), dataInLocalesAll(), referenceContentAllWithAttributes()) .orElseThrow(); assertEquals("01", product.getAttribute(ATTRIBUTE_EAN)); diff --git a/evita_functional_tests/src/test/java/io/evitadb/driver/EvitaClientTest.java b/evita_functional_tests/src/test/java/io/evitadb/driver/EvitaClientTest.java index 5da91927e..3c8f71b2b 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/driver/EvitaClientTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/driver/EvitaClientTest.java @@ -991,7 +991,7 @@ void shouldQueryOneSealedEntity(long seed, EvitaClient evitaClient, Map