From eba2fc6fd18d8d6b053be682986e3834e1bbdf2b Mon Sep 17 00:00:00 2001
From: Ivan Vakhrushev
Date: Mon, 11 Nov 2024 23:42:05 +0400
Subject: [PATCH] Add SkipIndexesByNamePredicate (#490)
* Add SkipIndexesByNamePredicate
* Refactor tests
---
.../host/IndexesWithBloatCheckOnHostTest.java | 5 +
.../IndexesWithBooleanCheckOnHostTest.java | 5 +
.../IndexesWithNullValuesCheckOnHostTest.java | 5 +
.../host/InvalidIndexesCheckOnHostTest.java | 5 +
.../host/UnusedIndexesCheckOnHostTest.java | 6 +-
.../AbstractSkipTablesPredicate.java | 44 +++++--
.../SkipBySequenceNamePredicate.java | 14 +--
.../SkipDbObjectsByNamePredicate.java | 3 +-
.../SkipIndexesByNamePredicate.java | 111 +++++++++++++++++
.../predicates/SkipTablesByNamePredicate.java | 4 +-
.../AbstractSkipTablesPredicateTest.java | 2 +-
.../SkipBySequenceNamePredicateTest.java | 4 +-
.../SkipIndexesByNamePredicateTest.java | 117 ++++++++++++++++++
.../SkipTablesByNamePredicateTest.java | 4 +-
.../FilterIndexesByNamePredicate.java | 2 +
.../IndexesWithBloatCheckOnClusterTest.java | 23 ++--
.../IndexesWithBooleanCheckOnClusterTest.java | 9 +-
...dexesWithNullValuesCheckOnClusterTest.java | 9 +-
.../InvalidIndexesCheckOnClusterTest.java | 9 +-
.../UnusedIndexesCheckOnClusterTest.java | 25 ++--
20 files changed, 343 insertions(+), 63 deletions(-)
create mode 100644 pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicate.java
create mode 100644 pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicateTest.java
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBloatCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBloatCheckOnHostTest.java
index 34c464c5..00290551 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBloatCheckOnHostTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBloatCheckOnHostTest.java
@@ -14,6 +14,7 @@
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.index.IndexWithBloat;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.StatisticsAwareTestBase;
import org.assertj.core.api.Assertions;
@@ -62,6 +63,10 @@ void onDatabaseWithThem(final String schemaName) {
assertThat(check)
.executing(ctx, SkipTablesByNamePredicate.of(ctx, List.of("accounts", "clients")))
.isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.of(ctx, List.of("accounts_account_number_key", "accounts_pkey", "clients_pkey", "i_clients_email_phone")))
+ .isEmpty();
});
}
}
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBooleanCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBooleanCheckOnHostTest.java
index d2386b5c..ba3d5280 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBooleanCheckOnHostTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithBooleanCheckOnHostTest.java
@@ -15,6 +15,7 @@
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.column.Column;
import io.github.mfvanek.pg.model.index.IndexWithColumns;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
@@ -51,6 +52,10 @@ void onDatabaseWithThem(final String schemaName) {
assertThat(check)
.executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "accounts"))
.isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.ofName(ctx, "i_accounts_deleted"))
+ .isEmpty();
});
}
}
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithNullValuesCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithNullValuesCheckOnHostTest.java
index f5cc6f91..c4630a08 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithNullValuesCheckOnHostTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/IndexesWithNullValuesCheckOnHostTest.java
@@ -14,6 +14,7 @@
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.index.IndexWithNulls;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
@@ -49,6 +50,10 @@ void onDatabaseWithThem(final String schemaName) {
assertThat(check)
.executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "clients"))
.isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.ofName(ctx, "i_clients_middle_name"))
+ .isEmpty();
});
}
}
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/InvalidIndexesCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/InvalidIndexesCheckOnHostTest.java
index cf336cea..870ed907 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/InvalidIndexesCheckOnHostTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/InvalidIndexesCheckOnHostTest.java
@@ -14,6 +14,7 @@
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.index.Index;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
@@ -48,6 +49,10 @@ void onDatabaseWithThem(final String schemaName) {
assertThat(check)
.executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "clients"))
.isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.ofName(ctx, "i_clients_last_name_first_name"))
+ .isEmpty();
});
}
}
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/UnusedIndexesCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/UnusedIndexesCheckOnHostTest.java
index ca90387f..aa401397 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/UnusedIndexesCheckOnHostTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/UnusedIndexesCheckOnHostTest.java
@@ -15,6 +15,7 @@
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.index.UnusedIndex;
import io.github.mfvanek.pg.model.predicates.SkipDbObjectsByNamePredicate;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
@@ -56,8 +57,9 @@ void onDatabaseWithThem(final String schemaName) {
.allMatch(i -> i.getIndexScans() == 0);
assertThat(check)
- .executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "accounts"))
- .hasSize(2);
+ .executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "accounts")
+ .and(SkipIndexesByNamePredicate.of(ctx, List.of("i_clients_last_first", "i_clients_last_name"))))
+ .isEmpty();
assertThat(check)
.executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "accounts")
diff --git a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicate.java b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicate.java
index 147c297f..fe45b5b8 100644
--- a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicate.java
+++ b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicate.java
@@ -13,6 +13,7 @@
import io.github.mfvanek.pg.model.DbObject;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.table.TableNameAware;
+import io.github.mfvanek.pg.model.validation.Validators;
import java.util.Collection;
import java.util.Locale;
@@ -59,12 +60,7 @@ abstract class AbstractSkipTablesPredicate implements Predicate {
* @throws NullPointerException if {@code pgContext} or {@code rawTableNamesToSkip} is null
*/
AbstractSkipTablesPredicate(@Nonnull final PgContext pgContext, @Nonnull final Collection rawTableNamesToSkip) {
- Objects.requireNonNull(pgContext, "pgContext cannot be null");
- this.fullyQualifiedTableNamesToSkip = Objects.requireNonNull(rawTableNamesToSkip, "rawTableNamesToSkip cannot be null")
- .stream()
- .map(pgContext::enrichWithSchema)
- .map(s -> s.toLowerCase(Locale.ROOT))
- .collect(Collectors.toUnmodifiableSet());
+ this.fullyQualifiedTableNamesToSkip = prepareFullyQualifiedNamesToSkip(pgContext, rawTableNamesToSkip);
}
/**
@@ -75,7 +71,7 @@ abstract class AbstractSkipTablesPredicate implements Predicate {
* Otherwise, returns {@code true}.
*
*
- * @param dbObject the object to be tested
+ * @param dbObject the database object to test; must be non-null
* @return {@code false} if the {@code DbObject} matches a table name in the skip set, {@code true} otherwise
*/
@Override
@@ -86,4 +82,38 @@ public boolean test(@Nonnull final DbObject dbObject) {
}
return true;
}
+
+ /**
+ * Prepares a set of fully qualified names to skip by enriching each raw name with schema information from the provided
+ * PostgreSQL context and converting it to lowercase for case-insensitive matching.
+ *
+ * @param pgContext the PostgreSQL context used to enrich each raw name with schema information; must be non-null
+ * @param rawNamesToSkip the collection of raw names to skip; must be non-null
+ * @return an unmodifiable {@link Set} of fully qualified names to skip, in lowercase
+ * @throws NullPointerException if {@code pgContext} or {@code rawNamesToSkip} is null
+ */
+ @Nonnull
+ static Set prepareFullyQualifiedNamesToSkip(@Nonnull final PgContext pgContext,
+ @Nonnull final Collection rawNamesToSkip) {
+ Objects.requireNonNull(pgContext, "pgContext cannot be null");
+ return Objects.requireNonNull(rawNamesToSkip, "rawNamesToSkip cannot be null")
+ .stream()
+ .map(pgContext::enrichWithSchema)
+ .map(s -> s.toLowerCase(Locale.ROOT))
+ .collect(Collectors.toUnmodifiableSet());
+ }
+
+ /**
+ * Prepares a set containing a single name to skip, after validating that it is non-blank.
+ *
+ * @param rawNameToSkip the raw name to skip; must be non-null and non-blank
+ * @param argumentName the name of the argument being checked
+ * @return a {@link Set} containing the single validated name to skip
+ * @throws IllegalArgumentException if {@code rawNameToSkip} is blank
+ * @throws NullPointerException if {@code rawNameToSkip} is null
+ */
+ @Nonnull
+ static Set prepareSingleNameToSkip(@Nonnull final String rawNameToSkip, @Nonnull final String argumentName) {
+ return Set.of(Validators.notBlank(rawNameToSkip, argumentName));
+ }
}
diff --git a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicate.java b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicate.java
index f1c2584e..b722498c 100644
--- a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicate.java
+++ b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicate.java
@@ -13,18 +13,17 @@
import io.github.mfvanek.pg.model.DbObject;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.sequence.SequenceNameAware;
-import io.github.mfvanek.pg.model.validation.Validators;
import java.util.Collection;
import java.util.Locale;
-import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
+import static io.github.mfvanek.pg.model.predicates.AbstractSkipTablesPredicate.prepareFullyQualifiedNamesToSkip;
+
/**
* A predicate that filters out database objects based on a specified set of sequence names.
*
@@ -40,16 +39,11 @@ public final class SkipBySequenceNamePredicate implements Predicate {
private final Set fullyQualifiedSequenceNamesToSkip;
private SkipBySequenceNamePredicate(@Nonnull final PgContext pgContext, @Nonnull final Collection rawSequenceNamesToSkip) {
- Objects.requireNonNull(pgContext, "pgContext cannot be null");
- this.fullyQualifiedSequenceNamesToSkip = Objects.requireNonNull(rawSequenceNamesToSkip, "rawSequenceNamesToSkip cannot be null")
- .stream()
- .map(pgContext::enrichWithSchema)
- .map(s -> s.toLowerCase(Locale.ROOT))
- .collect(Collectors.toUnmodifiableSet());
+ this.fullyQualifiedSequenceNamesToSkip = prepareFullyQualifiedNamesToSkip(pgContext, rawSequenceNamesToSkip);
}
private SkipBySequenceNamePredicate(@Nonnull final PgContext pgContext, @Nonnull final String rawSequenceNameToSkip) {
- this(pgContext, Set.of(Validators.notBlank(rawSequenceNameToSkip, "rawSequenceNameToSkip")));
+ this(pgContext, AbstractSkipTablesPredicate.prepareSingleNameToSkip(rawSequenceNameToSkip, "rawSequenceNameToSkip"));
}
/**
diff --git a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipDbObjectsByNamePredicate.java b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipDbObjectsByNamePredicate.java
index 00d89e38..591c2a26 100644
--- a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipDbObjectsByNamePredicate.java
+++ b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipDbObjectsByNamePredicate.java
@@ -11,7 +11,6 @@
package io.github.mfvanek.pg.model.predicates;
import io.github.mfvanek.pg.model.DbObject;
-import io.github.mfvanek.pg.model.validation.Validators;
import java.util.Collection;
import java.util.Locale;
@@ -53,7 +52,7 @@ private SkipDbObjectsByNamePredicate(@Nonnull final Collection fullyQual
}
private SkipDbObjectsByNamePredicate(@Nonnull final String fullyQualifiedObjectNameToSkip) {
- this(Set.of(Validators.notBlank(fullyQualifiedObjectNameToSkip, "fullyQualifiedObjectNameToSkip")));
+ this(AbstractSkipTablesPredicate.prepareSingleNameToSkip(fullyQualifiedObjectNameToSkip, "fullyQualifiedObjectNameToSkip"));
}
/**
diff --git a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicate.java b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicate.java
new file mode 100644
index 00000000..349258bf
--- /dev/null
+++ b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicate.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2019-2024. Ivan Vakhrushev and others.
+ * https://github.com/mfvanek/pg-index-health
+ *
+ * This file is a part of "pg-index-health" - a Java library for
+ * analyzing and maintaining indexes health in PostgreSQL databases.
+ *
+ * Licensed under the Apache License 2.0
+ */
+
+package io.github.mfvanek.pg.model.predicates;
+
+import io.github.mfvanek.pg.model.DbObject;
+import io.github.mfvanek.pg.model.PgContext;
+import io.github.mfvanek.pg.model.index.IndexNameAware;
+
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Set;
+import java.util.function.Predicate;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.Immutable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import static io.github.mfvanek.pg.model.predicates.AbstractSkipTablesPredicate.prepareFullyQualifiedNamesToSkip;
+
+/**
+ * A predicate that skips specified indexes by name in database objects implementing the {@link DbObject} interface.
+ * This class is immutable and thread-safe.
+ *
+ * It can be configured with either a single index name or a collection of index names to skip. The names are enriched
+ * with schema information, if available, to ensure they match the fully qualified index names in the database.
+ *
+ *
+ * @author Ivan Vakhrushev
+ * @see DbObject
+ * @see IndexNameAware
+ * @see PgContext
+ * @since 0.13.3
+ */
+@Immutable
+@ThreadSafe
+public final class SkipIndexesByNamePredicate implements Predicate {
+
+ private final Set fullyQualifiedIndexNamesToSkip;
+
+ private SkipIndexesByNamePredicate(@Nonnull final PgContext pgContext, @Nonnull final Collection rawIndexNamesToSkip) {
+ this.fullyQualifiedIndexNamesToSkip = prepareFullyQualifiedNamesToSkip(pgContext, rawIndexNamesToSkip);
+ }
+
+ private SkipIndexesByNamePredicate(@Nonnull final PgContext pgContext, @Nonnull final String rawIndexNameToSkip) {
+ this(pgContext, AbstractSkipTablesPredicate.prepareSingleNameToSkip(rawIndexNameToSkip, "rawIndexNameToSkip"));
+ }
+
+ /**
+ * Tests whether the specified {@code DbObject} should be skipped based on its index name.
+ *
+ * @param dbObject the database object to test; must be non-null
+ * @return {@code true} if the {@code dbObject}'s index name does not match any of the names to skip; {@code false} otherwise
+ */
+ @Override
+ public boolean test(@Nonnull final DbObject dbObject) {
+ if (!fullyQualifiedIndexNamesToSkip.isEmpty() && dbObject instanceof IndexNameAware) {
+ final IndexNameAware i = (IndexNameAware) dbObject;
+ return !fullyQualifiedIndexNamesToSkip.contains(i.getIndexName().toLowerCase(Locale.ROOT));
+ }
+ return true;
+ }
+
+ /**
+ * Creates a predicate to skip a single index name in the public schema.
+ *
+ * @param rawIndexNameToSkip the raw index name to skip; must be non-null and non-blank
+ * @return a {@link Predicate} to skip the specified index name
+ */
+ public static Predicate ofName(@Nonnull final String rawIndexNameToSkip) {
+ return new SkipIndexesByNamePredicate(PgContext.ofPublic(), rawIndexNameToSkip);
+ }
+
+ /**
+ * Creates a predicate to skip a collection of index names in the public schema.
+ *
+ * @param rawIndexNamesToSkip a collection of raw index names to skip; must be non-null
+ * @return a {@link Predicate} to skip the specified index names
+ */
+ public static Predicate of(@Nonnull final Collection rawIndexNamesToSkip) {
+ return new SkipIndexesByNamePredicate(PgContext.ofPublic(), rawIndexNamesToSkip);
+ }
+
+ /**
+ * Creates a predicate to skip a single index name in a specified schema context.
+ *
+ * @param pgContext the PostgreSQL context used to enrich the raw index name with schema information; must be non-null
+ * @param rawIndexNameToSkip the raw index name to skip; must be non-null and non-blank
+ * @return a {@link Predicate} to skip the specified index name
+ */
+ public static Predicate ofName(@Nonnull final PgContext pgContext, @Nonnull final String rawIndexNameToSkip) {
+ return new SkipIndexesByNamePredicate(pgContext, rawIndexNameToSkip);
+ }
+
+ /**
+ * Creates a predicate to skip a collection of index names in a specified schema context.
+ *
+ * @param pgContext the PostgreSQL context used to enrich each raw index name with schema information; must be non-null
+ * @param rawIndexNamesToSkip a collection of raw index names to skip; must be non-null
+ * @return a {@link Predicate} to skip the specified index names
+ */
+ public static Predicate of(@Nonnull final PgContext pgContext, @Nonnull final Collection rawIndexNamesToSkip) {
+ return new SkipIndexesByNamePredicate(pgContext, rawIndexNamesToSkip);
+ }
+}
diff --git a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicate.java b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicate.java
index 71b901bf..d6affc96 100644
--- a/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicate.java
+++ b/pg-index-health-model/src/main/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicate.java
@@ -12,10 +12,8 @@
import io.github.mfvanek.pg.model.DbObject;
import io.github.mfvanek.pg.model.PgContext;
-import io.github.mfvanek.pg.model.validation.Validators;
import java.util.Collection;
-import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
@@ -42,7 +40,7 @@ private SkipTablesByNamePredicate(@Nonnull final PgContext pgContext, @Nonnull f
}
private SkipTablesByNamePredicate(@Nonnull final PgContext pgContext, @Nonnull final String rawTableNameToSkip) {
- this(pgContext, Set.of(Validators.notBlank(rawTableNameToSkip, "rawTableNameToSkip")));
+ this(pgContext, prepareSingleNameToSkip(rawTableNameToSkip, "rawTableNameToSkip"));
}
/**
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicateTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicateTest.java
index 772e176a..50f2e695 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicateTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/AbstractSkipTablesPredicateTest.java
@@ -36,7 +36,7 @@ void shouldThrowExceptionWhenInvalidDataPassed() {
final PgContext ctx = PgContext.ofPublic();
assertThatThrownBy(() -> new SkipTablesPredicate(ctx, null))
.isInstanceOf(NullPointerException.class)
- .hasMessage("rawTableNamesToSkip cannot be null");
+ .hasMessage("rawNamesToSkip cannot be null");
}
@Test
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicateTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicateTest.java
index 541010a8..e6c5eae6 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicateTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipBySequenceNamePredicateTest.java
@@ -45,7 +45,7 @@ void shouldThrowExceptionWhenInvalidDataPassed() {
assertThatThrownBy(() -> SkipBySequenceNamePredicate.of(null))
.isInstanceOf(NullPointerException.class)
- .hasMessage("rawSequenceNamesToSkip cannot be null");
+ .hasMessage("rawNamesToSkip cannot be null");
assertThatThrownBy(() -> SkipBySequenceNamePredicate.of(null, null))
.isInstanceOf(NullPointerException.class)
@@ -54,7 +54,7 @@ void shouldThrowExceptionWhenInvalidDataPassed() {
final PgContext ctx = PgContext.ofPublic();
assertThatThrownBy(() -> SkipBySequenceNamePredicate.of(ctx, null))
.isInstanceOf(NullPointerException.class)
- .hasMessage("rawSequenceNamesToSkip cannot be null");
+ .hasMessage("rawNamesToSkip cannot be null");
assertThatThrownBy(() -> SkipBySequenceNamePredicate.ofName(ctx, null))
.isInstanceOf(NullPointerException.class)
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicateTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicateTest.java
new file mode 100644
index 00000000..d6b1ca32
--- /dev/null
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipIndexesByNamePredicateTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2019-2024. Ivan Vakhrushev and others.
+ * https://github.com/mfvanek/pg-index-health
+ *
+ * This file is a part of "pg-index-health" - a Java library for
+ * analyzing and maintaining indexes health in PostgreSQL databases.
+ *
+ * Licensed under the Apache License 2.0
+ */
+
+package io.github.mfvanek.pg.model.predicates;
+
+import io.github.mfvanek.pg.model.PgContext;
+import io.github.mfvanek.pg.model.column.Column;
+import io.github.mfvanek.pg.model.column.ColumnWithSerialType;
+import io.github.mfvanek.pg.model.index.Index;
+import io.github.mfvanek.pg.model.sequence.SequenceState;
+import io.github.mfvanek.pg.model.table.Table;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.Mockito;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class SkipIndexesByNamePredicateTest {
+
+ @SuppressWarnings("DataFlowIssue")
+ @Test
+ void shouldThrowExceptionWhenInvalidDataPassed() {
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.ofName(null))
+ .isInstanceOf(NullPointerException.class)
+ .hasMessage("rawIndexNameToSkip cannot be null");
+
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.ofName(""))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("rawIndexNameToSkip cannot be blank");
+
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.ofName(" "))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("rawIndexNameToSkip cannot be blank");
+
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.of(null))
+ .isInstanceOf(NullPointerException.class)
+ .hasMessage("rawNamesToSkip cannot be null");
+
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.of(null, null))
+ .isInstanceOf(NullPointerException.class)
+ .hasMessage("pgContext cannot be null");
+
+ final PgContext ctx = PgContext.ofPublic();
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.of(ctx, null))
+ .isInstanceOf(NullPointerException.class)
+ .hasMessage("rawNamesToSkip cannot be null");
+
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.ofName(ctx, null))
+ .isInstanceOf(NullPointerException.class)
+ .hasMessage("rawIndexNameToSkip cannot be null");
+
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.ofName(ctx, ""))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("rawIndexNameToSkip cannot be blank");
+
+ assertThatThrownBy(() -> SkipIndexesByNamePredicate.ofName(ctx, " "))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("rawIndexNameToSkip cannot be blank");
+ }
+
+ @Test
+ void shouldNotCastObjectsWhenExclusionsIsEmpty() {
+ final Index mockIndex = Mockito.mock(Index.class);
+ assertThat(SkipIndexesByNamePredicate.of(List.of()))
+ .accepts(mockIndex);
+ Mockito.verify(mockIndex, Mockito.never()).getIndexName();
+ }
+
+ @Test
+ void shouldWorkForSingleIndex() {
+ assertThat(SkipIndexesByNamePredicate.ofName("i2"))
+ .accepts(Table.of("t", 0L))
+ .accepts(Index.of("t1", "i1"))
+ .rejects(Index.of("t2", "i2"))
+ .rejects(Index.of("t2", "I2"));
+
+ final PgContext ctx = PgContext.of("CUSTOM");
+ assertThat(SkipIndexesByNamePredicate.ofName(ctx, "I2"))
+ .accepts(Table.of("custom.t", 0L))
+ .accepts(Index.of("custom.t1", "custom.i1"))
+ .rejects(Index.of("custom.t2", "custom.i2"))
+ .rejects(Index.of("custom.T2", "custom.I2"));
+ }
+
+ @Test
+ void shouldWorkForMultipleIndexes() {
+ assertThat(SkipIndexesByNamePredicate.of(Set.of("i1", "I2")))
+ .accepts(Table.of("t", 0L))
+ .accepts(SequenceState.of("s11", "int", 80.0))
+ .accepts(ColumnWithSerialType.ofSerial(Column.ofNullable("t", "c"), "s1"))
+ .rejects(Index.of("t1", "i1"))
+ .rejects(Index.of("t2", "i1"))
+ .rejects(Index.of("T2", "I2"));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
+ void shouldWorkWithCustomSchema(final String schemaName) {
+ final PgContext ctx = PgContext.of(schemaName);
+ assertThat(SkipIndexesByNamePredicate.of(ctx, Set.of("i1", "i2")))
+ .accepts(Table.of(ctx.enrichWithSchema("t"), 0L))
+ .accepts(Index.of(ctx.enrichWithSchema("t1"), ctx.enrichWithSchema("i11")))
+ .rejects(Index.of(ctx.enrichWithSchema("t2"), ctx.enrichWithSchema("i2")));
+ }
+}
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicateTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicateTest.java
index 7840303f..ed83ea00 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicateTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/predicates/SkipTablesByNamePredicateTest.java
@@ -42,7 +42,7 @@ void shouldThrowExceptionWhenInvalidDataPassed() {
assertThatThrownBy(() -> SkipTablesByNamePredicate.of(null))
.isInstanceOf(NullPointerException.class)
- .hasMessage("rawTableNamesToSkip cannot be null");
+ .hasMessage("rawNamesToSkip cannot be null");
assertThatThrownBy(() -> SkipTablesByNamePredicate.of(null, null))
.isInstanceOf(NullPointerException.class)
@@ -51,7 +51,7 @@ void shouldThrowExceptionWhenInvalidDataPassed() {
final PgContext ctx = PgContext.ofPublic();
assertThatThrownBy(() -> SkipTablesByNamePredicate.of(ctx, null))
.isInstanceOf(NullPointerException.class)
- .hasMessage("rawTableNamesToSkip cannot be null");
+ .hasMessage("rawNamesToSkip cannot be null");
assertThatThrownBy(() -> SkipTablesByNamePredicate.ofName(ctx, null))
.isInstanceOf(NullPointerException.class)
diff --git a/pg-index-health/src/main/java/io/github/mfvanek/pg/checks/predicates/FilterIndexesByNamePredicate.java b/pg-index-health/src/main/java/io/github/mfvanek/pg/checks/predicates/FilterIndexesByNamePredicate.java
index 3df7e874..d1ce35af 100644
--- a/pg-index-health/src/main/java/io/github/mfvanek/pg/checks/predicates/FilterIndexesByNamePredicate.java
+++ b/pg-index-health/src/main/java/io/github/mfvanek/pg/checks/predicates/FilterIndexesByNamePredicate.java
@@ -22,7 +22,9 @@
*
* @author Ivan Vakhrushev
* @since 0.6.0
+ * @deprecated This class has been replaced by {@link io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate}
*/
+@Deprecated(since = "0.13.3", forRemoval = true)
public class FilterIndexesByNamePredicate extends AbstractFilterByName implements Predicate {
private FilterIndexesByNamePredicate(@Nonnull final Collection exclusions) {
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBloatCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBloatCheckOnClusterTest.java
index 1126283f..bcddb1b4 100644
--- a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBloatCheckOnClusterTest.java
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBloatCheckOnClusterTest.java
@@ -11,13 +11,12 @@
package io.github.mfvanek.pg.checks.cluster;
import io.github.mfvanek.pg.checks.predicates.FilterIndexesByBloatPredicate;
-import io.github.mfvanek.pg.checks.predicates.FilterIndexesByNamePredicate;
-import io.github.mfvanek.pg.checks.predicates.FilterIndexesBySizePredicate;
import io.github.mfvanek.pg.common.maintenance.DatabaseCheckOnCluster;
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
-import io.github.mfvanek.pg.model.index.IndexSizeAware;
import io.github.mfvanek.pg.model.index.IndexWithBloat;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
+import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabasePopulator;
import io.github.mfvanek.pg.support.StatisticsAwareTestBase;
import org.assertj.core.api.Assertions;
@@ -25,7 +24,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
-import java.util.function.Predicate;
+import java.util.List;
import static io.github.mfvanek.pg.support.AbstractCheckOnClusterAssert.assertThat;
@@ -74,17 +73,13 @@ void onDatabaseWithThem(final String schemaName) {
.allMatch(i -> i.getIndexSizeInBytes() > 1L)
.allMatch(i -> i.getBloatSizeInBytes() > 1L && i.getBloatPercentage() >= 14);
- final Predicate predicate = FilterIndexesBySizePredicate.of(1L)
- .and(FilterIndexesByNamePredicate.of(ctx.enrichWithSchema("accounts_pkey")));
assertThat(check)
- .executing(ctx, predicate)
- .hasSize(3)
- .containsExactlyInAnyOrder(
- IndexWithBloat.of(accountsTableName, ctx.enrichWithSchema("accounts_account_number_key"), 0L, 0L, 0),
- IndexWithBloat.of(clientsTableName, ctx.enrichWithSchema("clients_pkey"), 0L, 0L, 0),
- IndexWithBloat.of(clientsTableName, ctx.enrichWithSchema("i_clients_email_phone"), 0L, 0L, 0))
- .allMatch(i -> i.getIndexSizeInBytes() > 1L)
- .allMatch(i -> i.getBloatSizeInBytes() > 1L && i.getBloatPercentage() >= 14);
+ .executing(ctx, SkipTablesByNamePredicate.of(ctx, List.of("accounts", "clients")))
+ .isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.of(ctx, List.of("accounts_account_number_key", "accounts_pkey", "clients_pkey", "i_clients_email_phone")))
+ .isEmpty();
assertThat(check)
.executing(ctx, FilterIndexesByBloatPredicate.of(1_000_000L, 50))
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBooleanCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBooleanCheckOnClusterTest.java
index d77ea13d..6c1a9fda 100644
--- a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBooleanCheckOnClusterTest.java
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithBooleanCheckOnClusterTest.java
@@ -10,12 +10,13 @@
package io.github.mfvanek.pg.checks.cluster;
-import io.github.mfvanek.pg.checks.predicates.FilterIndexesByNamePredicate;
import io.github.mfvanek.pg.common.maintenance.DatabaseCheckOnCluster;
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.column.Column;
import io.github.mfvanek.pg.model.index.IndexWithColumns;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
+import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -47,7 +48,11 @@ void onDatabaseWithThem(final String schemaName) {
Column.ofNotNull(ctx.enrichWithSchema("accounts"), "deleted")));
assertThat(check)
- .executing(ctx, FilterIndexesByNamePredicate.of(ctx.enrichWithSchema("i_accounts_deleted")))
+ .executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "accounts"))
+ .isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.ofName(ctx, "i_accounts_deleted"))
.isEmpty();
});
}
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithNullValuesCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithNullValuesCheckOnClusterTest.java
index 826f4991..3ad209a9 100644
--- a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithNullValuesCheckOnClusterTest.java
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/IndexesWithNullValuesCheckOnClusterTest.java
@@ -10,11 +10,12 @@
package io.github.mfvanek.pg.checks.cluster;
-import io.github.mfvanek.pg.checks.predicates.FilterIndexesByNamePredicate;
import io.github.mfvanek.pg.common.maintenance.DatabaseCheckOnCluster;
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.index.IndexWithNulls;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
+import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -55,7 +56,11 @@ void onDatabaseWithThem(final String schemaName) {
.allMatch(i -> i.getNullableColumn().isNullable());
assertThat(check)
- .executing(ctx, FilterIndexesByNamePredicate.of(ctx.enrichWithSchema("i_clients_middle_name")))
+ .executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "clients"))
+ .isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.ofName(ctx, "i_clients_middle_name"))
.isEmpty();
});
}
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/InvalidIndexesCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/InvalidIndexesCheckOnClusterTest.java
index 23ec408e..815ef5a2 100644
--- a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/InvalidIndexesCheckOnClusterTest.java
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/InvalidIndexesCheckOnClusterTest.java
@@ -10,11 +10,12 @@
package io.github.mfvanek.pg.checks.cluster;
-import io.github.mfvanek.pg.checks.predicates.FilterIndexesByNamePredicate;
import io.github.mfvanek.pg.common.maintenance.DatabaseCheckOnCluster;
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.index.Index;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
+import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -45,7 +46,11 @@ void onDatabaseWithThem(final String schemaName) {
Index.of(ctx.enrichWithSchema("clients"), ctx.enrichWithSchema("i_clients_last_name_first_name")));
assertThat(check)
- .executing(ctx, FilterIndexesByNamePredicate.of(ctx.enrichWithSchema("i_clients_last_name_first_name")))
+ .executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "clients"))
+ .isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipIndexesByNamePredicate.ofName(ctx, "i_clients_last_name_first_name"))
.isEmpty();
});
}
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/UnusedIndexesCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/UnusedIndexesCheckOnClusterTest.java
index 54f10a5d..f6ead534 100644
--- a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/UnusedIndexesCheckOnClusterTest.java
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/UnusedIndexesCheckOnClusterTest.java
@@ -10,12 +10,13 @@
package io.github.mfvanek.pg.checks.cluster;
-import io.github.mfvanek.pg.checks.predicates.FilterIndexesByNamePredicate;
import io.github.mfvanek.pg.common.maintenance.DatabaseCheckOnCluster;
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
-import io.github.mfvanek.pg.model.index.IndexNameAware;
import io.github.mfvanek.pg.model.index.UnusedIndex;
+import io.github.mfvanek.pg.model.predicates.SkipDbObjectsByNamePredicate;
+import io.github.mfvanek.pg.model.predicates.SkipIndexesByNamePredicate;
+import io.github.mfvanek.pg.model.predicates.SkipTablesByNamePredicate;
import io.github.mfvanek.pg.statistics.maintenance.StatisticsMaintenanceOnHost;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import io.github.mfvanek.pg.support.LogsCaptor;
@@ -29,7 +30,6 @@
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Optional;
-import java.util.function.Predicate;
import static io.github.mfvanek.pg.checks.cluster.UnusedIndexesCheckOnCluster.getLastStatsResetDateLogMessage;
import static io.github.mfvanek.pg.checks.cluster.UnusedIndexesCheckOnCluster.getResultAsIntersection;
@@ -77,18 +77,15 @@ void onDatabaseWithThem(final String schemaName) {
.allMatch(i -> i.getIndexSizeInBytes() > 0L)
.allMatch(i -> i.getIndexScans() == 0);
- final Predicate predicate = FilterIndexesByNamePredicate.of(
- List.of(ctx.enrichWithSchema("i_clients_last_first"), ctx.enrichWithSchema("i_accounts_account_number")));
assertThat(check)
- .executing(ctx, predicate)
- .hasSize(4)
- .containsExactlyInAnyOrder(
- UnusedIndex.of(ctx.enrichWithSchema("clients"), ctx.enrichWithSchema("i_clients_last_name"), 0L, 0),
- UnusedIndex.of(ctx.enrichWithSchema("accounts"), ctx.enrichWithSchema("i_accounts_number_balance_not_deleted"), 0L, 0),
- UnusedIndex.of(ctx.enrichWithSchema("accounts"), ctx.enrichWithSchema("i_accounts_account_number_not_deleted"), 0L, 0),
- UnusedIndex.of(ctx.enrichWithSchema("accounts"), ctx.enrichWithSchema("i_accounts_id_account_number_not_deleted"), 0L, 0))
- .allMatch(i -> i.getIndexSizeInBytes() > 0L)
- .allMatch(i -> i.getIndexScans() == 0);
+ .executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "accounts")
+ .and(SkipIndexesByNamePredicate.of(ctx, List.of("i_clients_last_first", "i_clients_last_name"))))
+ .isEmpty();
+
+ assertThat(check)
+ .executing(ctx, SkipTablesByNamePredicate.ofName(ctx, "accounts")
+ .and(SkipDbObjectsByNamePredicate.of(List.of(ctx.enrichWithSchema("i_clients_last_first"), ctx.enrichWithSchema("i_clients_last_name")))))
+ .isEmpty();
});
}