From 0b32a8195a59381d1fea2675456db92e12eacd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Novotn=C3=BD?= Date: Mon, 4 Nov 2024 10:25:08 +0100 Subject: [PATCH] fix(#728): Referenced entity sorting doesn't work correctly if language is part of the query (cherry picked from commit 0f9cd8700f2998d935c9a67bac11d20922f3ae1c) --- .../data/structure/EntityDecorator.java | 2 +- .../dto/SortableAttributeCompoundSchema.java | 4 +-- .../AttributeNaturalTranslator.java | 27 ++++++++++++++----- .../ReferencePredecessorComparator.java | 6 ++--- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityDecorator.java b/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityDecorator.java index c3e699d624..dd9e12f198 100644 --- a/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityDecorator.java +++ b/evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityDecorator.java @@ -171,12 +171,12 @@ private static void sortAndFilterSubList( final ReferenceDecorator[] filteredReferences = Arrays.stream(references, start, end) .filter(it -> referenceFilter.test(entityPrimaryKey, it)) .toArray(ReferenceDecorator[]::new); + Arrays.sort(filteredReferences, referenceComparator); for (int i = start; i < end; i++) { final int filteredIndex = i - start; references[i] = filteredReferences.length > filteredIndex ? filteredReferences[filteredIndex] : null; } - Arrays.sort(references, start, end, referenceComparator); } nonSortedReferenceCount = referenceComparator.getNonSortedReferenceCount(); start = start + (end - nonSortedReferenceCount); diff --git a/evita_api/src/main/java/io/evitadb/api/requestResponse/schema/dto/SortableAttributeCompoundSchema.java b/evita_api/src/main/java/io/evitadb/api/requestResponse/schema/dto/SortableAttributeCompoundSchema.java index e3318c5866..b53c7926d0 100644 --- a/evita_api/src/main/java/io/evitadb/api/requestResponse/schema/dto/SortableAttributeCompoundSchema.java +++ b/evita_api/src/main/java/io/evitadb/api/requestResponse/schema/dto/SortableAttributeCompoundSchema.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -123,7 +123,7 @@ private SortableAttributeCompoundSchema( * Part of PRIVATE API, because we need to ensure the `attributeSchemaProvider` always provide the same and correct * attribute schemas from the same entity schema version. */ - public boolean isLocalized(@Nonnull Function attributeSchemaProvider) { + public boolean isLocalized(@Nonnull Function attributeSchemaProvider) { if (this.memoizedLocalized == null) { this.memoizedLocalized = attributeElements .stream() diff --git a/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/AttributeNaturalTranslator.java b/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/AttributeNaturalTranslator.java index 6e774d7d71..80afe37eae 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/AttributeNaturalTranslator.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/AttributeNaturalTranslator.java @@ -30,6 +30,7 @@ import io.evitadb.api.requestResponse.schema.NamedSchemaContract; import io.evitadb.api.requestResponse.schema.SortableAttributeCompoundSchemaContract; import io.evitadb.api.requestResponse.schema.SortableAttributeCompoundSchemaContract.AttributeElement; +import io.evitadb.api.requestResponse.schema.dto.SortableAttributeCompoundSchema; import io.evitadb.core.query.AttributeSchemaAccessor.AttributeTrait; import io.evitadb.core.query.sort.EntityComparator; import io.evitadb.core.query.sort.OrderByVisitor; @@ -159,14 +160,18 @@ public void createComparator(@Nonnull AttributeNatural attributeNatural, @Nonnul ) { if (orderDirection == ASC) { comparator = new ReferencePredecessorComparator( - attributeOrCompoundName, locale, orderByVisitor, + attributeOrCompoundName, + attributeSchema.isLocalized() ? locale : null, + orderByVisitor, ChainIndex::getAscendingOrderRecordsSupplier, (ref1, ref2) -> ref1.primaryKey() == ref2.primaryKey(), (epk, referenceKey) -> epk ); } else { comparator = new ReferencePredecessorComparator( - attributeOrCompoundName, locale, orderByVisitor, + attributeOrCompoundName, + attributeSchema.isLocalized() ? locale : null, + orderByVisitor, ChainIndex::getDescendingOrderRecordsSupplier, (ref1, ref2) -> ref1.primaryKey() == ref2.primaryKey(), (epk, referenceKey) -> epk @@ -177,28 +182,36 @@ public void createComparator(@Nonnull AttributeNatural attributeNatural, @Nonnul ) { if (orderDirection == ASC) { comparator = new ReferencePredecessorComparator( - attributeOrCompoundName, locale, orderByVisitor, + attributeOrCompoundName, + attributeSchema.isLocalized() ? locale : null, + orderByVisitor, ChainIndex::getAscendingOrderRecordsSupplier, (ref1, ref2) -> true, (epk, referenceKey) -> referenceKey.primaryKey() ); } else { comparator = new ReferencePredecessorComparator( - attributeOrCompoundName, locale, orderByVisitor, + attributeOrCompoundName, + attributeSchema.isLocalized() ? locale : null, + orderByVisitor, ChainIndex::getDescendingOrderRecordsSupplier, (ref1, ref2) -> true, (epk, referenceKey) -> referenceKey.primaryKey() ); } - } else if (attributeOrCompoundSchema instanceof SortableAttributeCompoundSchemaContract compoundSchemaContract) { + } else if (attributeOrCompoundSchema instanceof SortableAttributeCompoundSchema compoundSchemaContract) { comparator = new ReferenceCompoundAttributeComparator( - compoundSchemaContract, locale, + compoundSchemaContract, + compoundSchemaContract.isLocalized(orderByVisitor::getAttributeSchema) ? locale : null, orderByVisitor::getAttributeSchema, orderDirection ); } else if (attributeOrCompoundSchema instanceof AttributeSchemaContract attributeSchema) { comparator = new ReferenceAttributeComparator( - attributeOrCompoundName, attributeSchema.getPlainType(), locale, orderDirection + attributeOrCompoundName, + attributeSchema.getPlainType(), + attributeSchema.isLocalized() ? locale : null, + orderDirection ); } else { throw new GenericEvitaInternalError("Unsupported attribute schema type: " + attributeOrCompoundSchema); diff --git a/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/ReferencePredecessorComparator.java b/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/ReferencePredecessorComparator.java index 461f3958fa..fc2c10b9e3 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/ReferencePredecessorComparator.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/sort/attribute/translator/ReferencePredecessorComparator.java @@ -218,11 +218,11 @@ private IntHashSet getNonSortedReferences() { * if not found in the cache. */ private int getRecordPosition(@Nonnull ReferenceKey referenceKey) { - final int pkToLookup = primaryKeyResolver.applyAsInt(this.entityPrimaryKey, referenceKey); + final int pkToLookup = this.primaryKeyResolver.applyAsInt(this.entityPrimaryKey, referenceKey); final int position = this.pkToRecordPositionCache.getOrDefault(pkToLookup, -1); if (position == -1) { - final ChainIndex chainIndex = this.referenceOrderByVisitor.getChainIndex(this.entityPrimaryKey, referenceKey, attributeKey).orElse(null); - final SortedRecordsProvider sortedRecordsSupplier = chainIndex == null ? SortedRecordsProvider.EMPTY : sortedRecordsSupplierProvider.apply(chainIndex); + final ChainIndex chainIndex = this.referenceOrderByVisitor.getChainIndex(this.entityPrimaryKey, referenceKey, this.attributeKey).orElse(null); + final SortedRecordsProvider sortedRecordsSupplier = chainIndex == null ? SortedRecordsProvider.EMPTY : this.sortedRecordsSupplierProvider.apply(chainIndex); final int index = sortedRecordsSupplier.getAllRecords().indexOf(pkToLookup); final int computedPosition = index < 0 ? -2 : sortedRecordsSupplier.getRecordPositions()[index]; this.pkToRecordPositionCache.put(pkToLookup, computedPosition);