Skip to content

Commit

Permalink
fix(#677): added last missing rename
Browse files Browse the repository at this point in the history
Fixed global entity indexes recognition in TargetIndexes. There may be multiple ones now (for different scopes).
  • Loading branch information
novoj committed Nov 22, 2024
1 parent 2ffb431 commit a5d5679
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ default boolean isUniqueGloballyInAnyScope() {
* @return true if the attribute is unique globally within the default (i.e. {@link Scope#LIVE})} scope
*/
default boolean isUniqueGloballyWithinLocale() {
return isUniqueGloballyWithinLocale(Scope.DEFAULT_SCOPE);
return isUniqueGloballyWithinLocaleInScope(Scope.DEFAULT_SCOPE);
}

/**
Expand All @@ -115,7 +115,7 @@ default boolean isUniqueGloballyWithinLocale() {
* @return true if the attribute is unique globally within any scope
*/
default boolean isUniqueGloballyWithinLocaleInAnyScope() {
return Arrays.stream(Scope.values()).anyMatch(this::isUniqueGloballyWithinLocale);
return Arrays.stream(Scope.values()).anyMatch(this::isUniqueGloballyWithinLocaleInScope);
}

/**
Expand All @@ -133,7 +133,7 @@ default boolean isUniqueGloballyWithinLocaleInAnyScope() {
* @param scope scope to check uniqueness in
* @return true if the attribute is unique globally within particular scope
*/
boolean isUniqueGloballyWithinLocale(@Nonnull Scope scope);
boolean isUniqueGloballyWithinLocaleInScope(@Nonnull Scope scope);

/**
* Returns type of uniqueness of the attribute. See {@link #isUniqueGlobally()} and {@link #isUniqueGloballyWithinLocale()}.
Expand All @@ -143,6 +143,7 @@ default boolean isUniqueGloballyWithinLocaleInAnyScope() {
default GlobalAttributeUniquenessType getGlobalUniquenessType() {
return getGlobalUniquenessType(Scope.DEFAULT_SCOPE);
}

/**
* Returns type of uniqueness of the attribute. See {@link #isUniqueGlobally()} and {@link #isUniqueGloballyWithinLocale()}.
* @return type of uniqueness in the particular scope
Expand All @@ -157,5 +158,4 @@ default GlobalAttributeUniquenessType getGlobalUniquenessType() {
*/
@Nonnull
Map<Scope, GlobalAttributeUniquenessType> getGlobalUniquenessTypeInScopes();

}
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public boolean isUniqueGloballyInScope(@Nonnull Scope scope) {
}

@Override
public boolean isUniqueGloballyWithinLocale(@Nonnull Scope scope) {
public boolean isUniqueGloballyWithinLocaleInScope(@Nonnull Scope scope) {
return this.globalUniquenessTypeInScopes.get(scope) == GlobalAttributeUniquenessType.UNIQUE_WITHIN_CATALOG_LOCALE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ public Optional<Runnable> createPrefetchLambdaIfNeededOrWorthwhile(@Nonnull Quer
EntityFetchRequire requirements = null;
Bitmap entitiesToPrefetch = null;
// are we forced to prefetch entities from catalog index?
if (!entityReferences.isEmpty()) {
if (!this.entityReferences.isEmpty()) {
requirements = getRequirements();
entitiesToPrefetch = entityReferences;
entitiesToPrefetch = this.entityReferences;
}
// do we know entity ids to prefetch?
if (isPrefetchPossible()) {
Expand All @@ -154,18 +154,18 @@ public Optional<Runnable> createPrefetchLambdaIfNeededOrWorthwhile(@Nonnull Quer
RoaringBitmap.or(roaringBitmapA, roaringBitmapB)
);
}
if (!(targetIndexes.isGlobalIndex() || targetIndexes.isCatalogIndex())) {
if (!(this.targetIndexes.isGlobalIndex() || this.targetIndexes.isCatalogIndex())) {
// when narrowed indexes were used we need to filter the prefetched primary keys to the ones that are
// present in the index
Assert.isPremiseValid(
ReducedEntityIndex.class.isAssignableFrom(targetIndexes.getIndexType()),
ReducedEntityIndex.class.isAssignableFrom(this.targetIndexes.getIndexType()),
"Only reduced entity indexes are supported"
);
entitiesToPrefetch = RoaringBitmapBackedBitmap.and(
new RoaringBitmap[]{
RoaringBitmapBackedBitmap.getRoaringBitmap(entitiesToPrefetch),
RoaringBitmap.or(
targetIndexes.getIndexes().stream()
this.targetIndexes.getIndexes().stream()
.map(index -> ((ReducedEntityIndex) index).getAllPrimaryKeys())
.map(RoaringBitmapBackedBitmap::getRoaringBitmap)
.toArray(RoaringBitmap[]::new)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -87,7 +87,7 @@ public String toStringWithCosts(long estimatedCost) {
* Returns true if the largest global index was selected.
*/
public boolean isGlobalIndex() {
return this.indexes.size() == 1 && this.indexes.get(0) instanceof GlobalEntityIndex;
return this.indexes.stream().allMatch(GlobalEntityIndex.class::isInstance);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions evita_engine/src/main/java/io/evitadb/index/CatalogIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public void removeUniqueAttribute(
*/
@Nullable
public GlobalUniqueIndex getGlobalUniqueIndex(@Nonnull GlobalAttributeSchemaContract attributeSchema, @Nullable Locale locale) {
final boolean uniqueGloballyWithinLocale = attributeSchema.isUniqueGloballyWithinLocale(getIndexKey().scope());
final boolean uniqueGloballyWithinLocale = attributeSchema.isUniqueGloballyWithinLocaleInScope(getIndexKey().scope());
Assert.isTrue(
locale != null || !uniqueGloballyWithinLocale,
() -> new EntityLocaleMissingException(attributeSchema.getName())
Expand Down Expand Up @@ -320,7 +320,7 @@ private static AttributeKey createAttributeKey(
if (attributeSchema.isLocalized()) {
verifyLocalizedAttribute(attributeSchema.getName(), allowedLocales, locale, value);
}
if (attributeSchema.isUniqueGloballyWithinLocale(scope)) {
if (attributeSchema.isUniqueGloballyWithinLocaleInScope(scope)) {
return new AttributeKey(attributeSchema.getName(), locale);
} else {
return new AttributeKey(attributeSchema.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ private static Arguments from(@Nonnull DataFetchingEnvironment environment, @Non
globallyUniqueAttributes.keySet()
.stream()
.anyMatch(attribute ->
attribute.isUniqueGloballyWithinLocale(scope)))) {
attribute.isUniqueGloballyWithinLocaleInScope(scope)))) {
throw new GraphQLInvalidArgumentException("Globally unique within locale attribute used but no locale was passed.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ private static Arguments from(@Nonnull DataFetchingEnvironment environment, @Non
globallyUniqueAttributes.keySet()
.stream()
.anyMatch(attribute ->
attribute.isUniqueGloballyWithinLocale(scope)))) {
attribute.isUniqueGloballyWithinLocaleInScope(scope)))) {
throw new GraphQLInvalidArgumentException("Globally unique within locale attribute used but no locale was passed.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public static FilterBy buildFilterByForUnknownEntity(@Nonnull Map<String, Object
uniqueAttributes.keySet()
.stream()
.anyMatch(attribute ->
attribute.isUniqueGloballyWithinLocale(scope)))) {
attribute.isUniqueGloballyWithinLocaleInScope(scope)))) {
throw new RestInvalidArgumentException("Globally unique within locale attribute used but no locale was passed.");
}

Expand Down Expand Up @@ -216,7 +216,7 @@ public static FilterBy buildFilterByForUnknownEntityList(@Nonnull Map<String, Ob
uniqueAttributes.keySet()
.stream()
.anyMatch(attribute ->
attribute.isUniqueGloballyWithinLocale(scope)))) {
attribute.isUniqueGloballyWithinLocaleInScope(scope)))) {
throw new RestInvalidArgumentException("Globally unique within locale attribute used but no locale was passed.");
}

Expand Down
88 changes: 88 additions & 0 deletions evita_functional_tests/src/test/java/io/evitadb/api/EvitaTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import io.evitadb.api.exception.InvalidSchemaMutationException;
import io.evitadb.api.exception.UnexpectedResultCountException;
import io.evitadb.api.exception.UnexpectedResultException;
import io.evitadb.api.exception.UniqueValueViolationException;
import io.evitadb.api.file.FileForFetch;
import io.evitadb.api.mock.MockCatalogStructuralChangeObserver;
import io.evitadb.api.query.order.OrderDirection;
Expand Down Expand Up @@ -2469,6 +2470,93 @@ void shouldProperlyHandleFetchingOfNotYetKnownEntities() {
);
}

@Test
void shouldCorrectlyLocalizeGloballyUniqueAttribute() {
evita.defineCatalog(TEST_CATALOG)
.withAttribute(ATTRIBUTE_URL, String.class, whichIs -> whichIs.localized().uniqueGlobally())
.updateViaNewSession(evita);
evita.updateCatalog(
TEST_CATALOG,
session -> {
session
.defineEntitySchema(Entities.PRODUCT)
.withGlobalAttribute(ATTRIBUTE_URL)
.updateVia(session);

session.upsertEntity(
session.createNewEntity(Entities.PRODUCT, 1)
.setAttribute(ATTRIBUTE_URL, Locale.ENGLISH, "/theProduct")
);
}
);

assertThrows(
UniqueValueViolationException.class,
() -> evita.updateCatalog(
TEST_CATALOG,
session -> {
session.upsertEntity(
session.createNewEntity(Entities.PRODUCT, 2)
.setAttribute(ATTRIBUTE_URL, Locale.ENGLISH, "/theProduct")
);
}
)
);

assertEquals(
new EntityReference(Entities.PRODUCT, 1),
evita.queryCatalog(
TEST_CATALOG,
session -> {
return session.queryOne(
query(
collection(Entities.PRODUCT),
filterBy(attributeEquals(ATTRIBUTE_URL, "/theProduct"))
),
EntityReference.class
).orElseThrow();
}
)
);

assertEquals(
new EntityReference(Entities.PRODUCT, 1),
evita.queryCatalog(
TEST_CATALOG,
session -> {
return session.queryOne(
query(
collection(Entities.PRODUCT),
filterBy(
attributeEquals(ATTRIBUTE_URL, "/theProduct"),
entityLocaleEquals(Locale.ENGLISH)
)
),
EntityReference.class
).orElseThrow();
}
)
);

assertNull(
evita.queryCatalog(
TEST_CATALOG,
session -> {
return session.queryOne(
query(
collection(Entities.PRODUCT),
filterBy(
attributeEquals(ATTRIBUTE_URL, "/theProduct"),
entityLocaleEquals(Locale.FRENCH)
)
),
EntityReference.class
).orElse(null);
}
)
);
}

@Test
void shouldCreateBackupAndRestoreCatalog() throws IOException, ExecutionException, InterruptedException {
setupCatalogWithProductAndCategory();
Expand Down

0 comments on commit a5d5679

Please sign in to comment.