-
-
-
+
+
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 66c2e51d..7ceb23db 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -5,8 +5,8 @@ commons-lang3 = "3.17.0"
slf4j = "1.7.36" # to be compatible with Spring Boot 2.7.X
assertj = "3.26.3"
testcontainers = "1.20.3"
-junit = "5.11.2"
-mockito = "5.14.1"
+junit = "5.11.3"
+mockito = "5.14.2"
forbiddenapis = "3.8"
[libraries]
diff --git a/pg-index-health-core/src/main/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHost.java b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHost.java
index e603f5af..c34bb50b 100644
--- a/pg-index-health-core/src/main/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHost.java
+++ b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHost.java
@@ -33,6 +33,8 @@ public ForeignKeysNotCoveredWithIndexCheckOnHost(@Nonnull final PgConnection pgC
/**
* Returns foreign keys without associated indexes in the specified schema.
+ *
+ * For multi-column constraints returns all columns.
*
* @param pgContext check's context with the specified schema
* @return list of foreign keys without associated indexes
diff --git a/pg-index-health-core/src/main/java/io/github/mfvanek/pg/checks/host/ForeignKeysWithUnmatchedColumnTypeCheckOnHost.java b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/checks/host/ForeignKeysWithUnmatchedColumnTypeCheckOnHost.java
new file mode 100644
index 00000000..0ba16eb1
--- /dev/null
+++ b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/checks/host/ForeignKeysWithUnmatchedColumnTypeCheckOnHost.java
@@ -0,0 +1,53 @@
+/*
+ * 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.checks.host;
+
+import io.github.mfvanek.pg.checks.extractors.ForeignKeyExtractor;
+import io.github.mfvanek.pg.common.maintenance.Diagnostic;
+import io.github.mfvanek.pg.connection.PgConnection;
+import io.github.mfvanek.pg.model.PgContext;
+import io.github.mfvanek.pg.model.constraint.ForeignKey;
+
+import java.util.List;
+import javax.annotation.Nonnull;
+
+/**
+ * Check for foreign keys where the type of the constrained column does not match the type in the referenced table on a specific host.
+ *
+ * The column types in the referring and target relation must match.
+ * For example, a column with the {@code integer} type should refer to a column with the {@code integer} type.
+ * This eliminates unnecessary conversions at the DBMS level and in the application code,
+ * and reduces the number of errors that may appear due to type inconsistencies in the future.
+ *
+ * @author Ivan Vahrushev
+ * @see pg_constraint
+ * @since 0.13.2
+ */
+public class ForeignKeysWithUnmatchedColumnTypeCheckOnHost extends AbstractCheckOnHost {
+
+ public ForeignKeysWithUnmatchedColumnTypeCheckOnHost(@Nonnull final PgConnection pgConnection) {
+ super(ForeignKey.class, pgConnection, Diagnostic.FOREIGN_KEYS_WITH_UNMATCHED_COLUMN_TYPE);
+ }
+
+ /**
+ * Returns foreign keys where the type of the constrained column does not match the type in the referenced table.
+ *
+ * For multi-column constraints returns only columns with differences.
+ *
+ * @param pgContext check's context with the specified schema; must not be null
+ * @return list of foreign keys where the type of the constrained column does not match the type in the referenced table
+ */
+ @Nonnull
+ @Override
+ protected List doCheck(@Nonnull final PgContext pgContext) {
+ return executeQuery(pgContext, ForeignKeyExtractor.ofDefault());
+ }
+}
diff --git a/pg-index-health-core/src/main/java/io/github/mfvanek/pg/common/maintenance/Diagnostic.java b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/common/maintenance/Diagnostic.java
index a6eb9c8b..61fc70cf 100644
--- a/pg-index-health-core/src/main/java/io/github/mfvanek/pg/common/maintenance/Diagnostic.java
+++ b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/common/maintenance/Diagnostic.java
@@ -47,7 +47,8 @@ public enum Diagnostic implements CheckTypeAware {
DUPLICATED_FOREIGN_KEYS(ExecutionTopology.ON_PRIMARY, "duplicated_foreign_keys.sql", QueryExecutors::executeQueryWithSchema, false),
INTERSECTED_FOREIGN_KEYS(ExecutionTopology.ON_PRIMARY, "intersected_foreign_keys.sql", QueryExecutors::executeQueryWithSchema, false),
POSSIBLE_OBJECT_NAME_OVERFLOW(ExecutionTopology.ON_PRIMARY, "possible_object_name_overflow.sql", QueryExecutors::executeQueryWithSchema, false),
- TABLES_NOT_LINKED_TO_OTHERS(ExecutionTopology.ON_PRIMARY, "tables_not_linked_to_others.sql", QueryExecutors::executeQueryWithSchema, false);
+ TABLES_NOT_LINKED_TO_OTHERS(ExecutionTopology.ON_PRIMARY, "tables_not_linked_to_others.sql", QueryExecutors::executeQueryWithSchema, false),
+ FOREIGN_KEYS_WITH_UNMATCHED_COLUMN_TYPE(ExecutionTopology.ON_PRIMARY, "foreign_keys_with_unmatched_column_type.sql", QueryExecutors::executeQueryWithSchema, false);
private final ExecutionTopology executionTopology;
private final String sqlQueryFileName;
diff --git a/pg-index-health-core/src/main/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParser.java b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParser.java
index 28cd6a08..35dbf573 100644
--- a/pg-index-health-core/src/main/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParser.java
+++ b/pg-index-health-core/src/main/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParser.java
@@ -39,14 +39,14 @@ public static List parseRawColumnData(@Nonnull final String tableName, @
@Nonnull
private static Column toColumn(@Nonnull final String tableName, @Nonnull final String rawColumnInfo) {
- final String[] columnInfo = rawColumnInfo.split(", ");
+ final String[] columnInfo = rawColumnInfo.split(",");
if (columnInfo.length != 2) {
throw new IllegalArgumentException("Cannot parse column info from " + rawColumnInfo);
}
- final boolean notNullColumn = Boolean.parseBoolean(columnInfo[1]);
+ final boolean notNullColumn = Boolean.parseBoolean(columnInfo[1].trim());
if (notNullColumn) {
- return Column.ofNotNull(tableName, columnInfo[0]);
+ return Column.ofNotNull(tableName, columnInfo[0].trim());
}
- return Column.ofNullable(tableName, columnInfo[0]);
+ return Column.ofNullable(tableName, columnInfo[0].trim());
}
}
diff --git a/pg-index-health-core/src/main/resources b/pg-index-health-core/src/main/resources
index 0f42870e..3b0f227f 160000
--- a/pg-index-health-core/src/main/resources
+++ b/pg-index-health-core/src/main/resources
@@ -1 +1 @@
-Subproject commit 0f42870e034eeb4886d2569bfd4e1226c79f0204
+Subproject commit 3b0f227f8f9f4abb29ae48fca52a4421fe2e4bd6
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHostTest.java
index 7c492199..62c87c12 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHostTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/ForeignKeysNotCoveredWithIndexCheckOnHostTest.java
@@ -20,6 +20,8 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
+import java.util.List;
+
import static io.github.mfvanek.pg.support.AbstractCheckOnHostAssert.assertThat;
class ForeignKeysNotCoveredWithIndexCheckOnHostTest extends DatabaseAwareTestBase {
@@ -38,39 +40,43 @@ void shouldSatisfyContract() {
@ParameterizedTest
@ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
void onDatabaseWithThem(final String schemaName) {
- executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withForeignKeyOnNullableColumn(), ctx ->
+ executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withForeignKeyOnNullableColumn(), ctx -> {
+ final String accountsTableName = ctx.enrichWithSchema("accounts");
+ final String badClientsTableName = ctx.enrichWithSchema("bad_clients");
assertThat(check)
.executing(ctx)
- .hasSize(2)
+ .hasSize(3)
.containsExactlyInAnyOrder(
- ForeignKey.ofColumn(ctx.enrichWithSchema("accounts"), "c_accounts_fk_client_id",
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id")),
- ForeignKey.ofColumn(ctx.enrichWithSchema("bad_clients"), "c_bad_clients_fk_real_client_id",
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id")))
+ ForeignKey.ofColumn(accountsTableName, "c_accounts_fk_client_id",
+ Column.ofNotNull(accountsTableName, "client_id")),
+ ForeignKey.ofColumn(badClientsTableName, "c_bad_clients_fk_real_client_id",
+ Column.ofNullable(badClientsTableName, "real_client_id")),
+ ForeignKey.of(badClientsTableName, "c_bad_clients_fk_email_phone",
+ List.of(
+ Column.ofNullable(badClientsTableName, "email"),
+ Column.ofNullable(badClientsTableName, "phone"))))
.flatExtracting(ForeignKey::getColumnsInConstraint)
- .hasSize(2)
+ .hasSize(4)
.containsExactlyInAnyOrder(
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id"),
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id")));
+ Column.ofNotNull(accountsTableName, "client_id"),
+ Column.ofNullable(badClientsTableName, "real_client_id"),
+ Column.ofNullable(badClientsTableName, "email"),
+ Column.ofNullable(badClientsTableName, "phone"));
+ });
}
@ParameterizedTest
@ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
void onDatabaseWithNotSuitableIndex(final String schemaName) {
- executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withForeignKeyOnNullableColumn().withNonSuitableIndex(), ctx ->
+ executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withNonSuitableIndex(), ctx -> {
+ final String accountsTableName = ctx.enrichWithSchema("accounts");
assertThat(check)
.executing(ctx)
- .hasSize(2)
- .containsExactlyInAnyOrder(
- ForeignKey.ofColumn(ctx.enrichWithSchema("accounts"), "c_accounts_fk_client_id",
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id")),
- ForeignKey.ofColumn(ctx.enrichWithSchema("bad_clients"), "c_bad_clients_fk_real_client_id",
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id")))
- .flatExtracting(ForeignKey::getColumnsInConstraint)
- .hasSize(2)
- .containsExactlyInAnyOrder(
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id"),
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id")));
+ .hasSize(1)
+ .containsExactly(
+ ForeignKey.ofColumn(accountsTableName, "c_accounts_fk_client_id",
+ Column.ofNotNull(accountsTableName, "client_id")));
+ });
}
@ParameterizedTest
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/ForeignKeysWithUnmatchedColumnTypeCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/ForeignKeysWithUnmatchedColumnTypeCheckOnHostTest.java
new file mode 100644
index 00000000..5e4686e2
--- /dev/null
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/ForeignKeysWithUnmatchedColumnTypeCheckOnHostTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.checks.host;
+
+import io.github.mfvanek.pg.common.maintenance.DatabaseCheckOnHost;
+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.constraint.ForeignKey;
+import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static io.github.mfvanek.pg.support.AbstractCheckOnHostAssert.assertThat;
+
+class ForeignKeysWithUnmatchedColumnTypeCheckOnHostTest extends DatabaseAwareTestBase {
+
+ private final DatabaseCheckOnHost check = new ForeignKeysWithUnmatchedColumnTypeCheckOnHost(getPgConnection());
+
+ @Test
+ void shouldSatisfyContract() {
+ assertThat(check)
+ .hasType(ForeignKey.class)
+ .hasDiagnostic(Diagnostic.FOREIGN_KEYS_WITH_UNMATCHED_COLUMN_TYPE)
+ .hasHost(getHost())
+ .isStatic();
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
+ void onDatabaseWithThem(final String schemaName) {
+ executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withForeignKeyOnNullableColumn(), ctx -> {
+ final String badClientsTableName = ctx.enrichWithSchema("bad_clients");
+ assertThat(check)
+ .executing(ctx)
+ .hasSize(2)
+ .containsExactlyInAnyOrder(
+ ForeignKey.ofColumn(badClientsTableName, "c_bad_clients_fk_real_client_id",
+ Column.ofNullable(badClientsTableName, "real_client_id")),
+ ForeignKey.ofColumn(badClientsTableName, "c_bad_clients_fk_email_phone",
+ Column.ofNullable(badClientsTableName, "phone"))
+ );
+ });
+ }
+}
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/TablesWithoutPrimaryKeyCheckOnHostTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/TablesWithoutPrimaryKeyCheckOnHostTest.java
index 8a01f634..d98de363 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/TablesWithoutPrimaryKeyCheckOnHostTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/checks/host/TablesWithoutPrimaryKeyCheckOnHostTest.java
@@ -44,9 +44,7 @@ void onDatabaseWithThem(final String schemaName) {
assertThat(check)
.executing(ctx)
.hasSize(1)
- .containsExactly(
- Table.of(ctx.enrichWithSchema("bad_clients"), 0L))
- .allMatch(t -> t.getTableSizeInBytes() == 0L));
+ .containsExactly(Table.of(ctx.enrichWithSchema("bad_clients"), 0L)));
}
@ParameterizedTest
diff --git a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParserTest.java b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParserTest.java
index ac7c02b7..a6d920ec 100644
--- a/pg-index-health-core/src/test/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParserTest.java
+++ b/pg-index-health-core/src/test/java/io/github/mfvanek/pg/utils/ColumnsInForeignKeyParserTest.java
@@ -54,4 +54,25 @@ void shouldWorkWhenValidDataPassed() {
Column.ofNullable("t", "c3"))
.isUnmodifiable();
}
+
+ @Test
+ void shouldWorkWithoutSpaces() {
+ assertThat(ColumnsInForeignKeyParser.parseRawColumnData("t", "c1,true", "c2,false", "c3,abracadabra"))
+ .hasSize(3)
+ .containsExactly(
+ Column.ofNotNull("t", "c1"),
+ Column.ofNullable("t", "c2"),
+ Column.ofNullable("t", "c3"))
+ .isUnmodifiable();
+ }
+
+ @Test
+ void shouldWorkWithExtraSpaces() {
+ assertThat(ColumnsInForeignKeyParser.parseRawColumnData("t", " c1, true ", " c2, false "))
+ .hasSize(2)
+ .containsExactly(
+ Column.ofNotNull("t", "c1"),
+ Column.ofNullable("t", "c2"))
+ .isUnmodifiable();
+ }
}
diff --git a/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateForeignKeyOnNullableColumnStatement.java b/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateForeignKeyOnNullableColumnStatement.java
index 86bc25a9..00cfb3c2 100644
--- a/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateForeignKeyOnNullableColumnStatement.java
+++ b/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateForeignKeyOnNullableColumnStatement.java
@@ -18,7 +18,11 @@ public class CreateForeignKeyOnNullableColumnStatement extends AbstractDbStateme
@Nonnull
@Override
protected List getSqlToExecute() {
- return List.of("alter table if exists {schemaName}.bad_clients " +
- "add constraint c_bad_clients_fk_real_client_id foreign key (real_client_id) references {schemaName}.clients (id);");
+ return List.of(
+ "alter table if exists {schemaName}.bad_clients " +
+ "add constraint c_bad_clients_fk_real_client_id foreign key (real_client_id) references {schemaName}.clients (id);",
+ "alter table if exists {schemaName}.bad_clients " +
+ "add constraint c_bad_clients_fk_email_phone foreign key (email, phone) references {schemaName}.clients (email, phone);"
+ );
}
}
diff --git a/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateTableWithoutPrimaryKeyStatement.java b/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateTableWithoutPrimaryKeyStatement.java
index 3f91a676..9a215cbb 100644
--- a/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateTableWithoutPrimaryKeyStatement.java
+++ b/pg-index-health-core/src/testFixtures/java/io/github/mfvanek/pg/support/statements/CreateTableWithoutPrimaryKeyStatement.java
@@ -23,7 +23,9 @@ protected List getSqlToExecute() {
return List.of("create table if not exists {schemaName}.bad_clients (" +
"id bigint not null, " +
"name varchar(255) not null," +
- "real_client_id bigint)");
+ "real_client_id integer," +
+ "email varchar(200)," +
+ "phone varchar(51))");
}
@Override
diff --git a/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/ConnectionCredentialsTest.java b/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/ConnectionCredentialsTest.java
index 4b3b9038..21f135fe 100644
--- a/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/ConnectionCredentialsTest.java
+++ b/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/ConnectionCredentialsTest.java
@@ -100,7 +100,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(ConnectionCredentials.class)
.verify();
diff --git a/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgConnectionImplTest.java b/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgConnectionImplTest.java
index d49ef41c..201a36ff 100644
--- a/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgConnectionImplTest.java
+++ b/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgConnectionImplTest.java
@@ -84,7 +84,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(PgConnectionImpl.class)
.withIgnoredFields("dataSource")
diff --git a/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgHostImplTest.java b/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgHostImplTest.java
index 5edbaec1..616ab897 100644
--- a/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgHostImplTest.java
+++ b/pg-index-health-jdbc-connection/src/test/java/io/github/mfvanek/pg/connection/PgHostImplTest.java
@@ -125,7 +125,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(PgHostImpl.class)
.withIgnoredFields("pgUrl", "maybePrimary")
diff --git a/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/AbstractHealthLogger.java b/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/AbstractHealthLogger.java
index 1109d1b8..97b37297 100644
--- a/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/AbstractHealthLogger.java
+++ b/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/AbstractHealthLogger.java
@@ -113,6 +113,7 @@ public final List logAll(@Nonnull final Exclusions exclusions,
logResult.add(logCheckResult(Diagnostic.INTERSECTED_FOREIGN_KEYS, DuplicatedForeignKeys.class, SimpleLoggingKey.INTERSECTED_FOREIGN_KEYS));
logResult.add(logCheckResult(Diagnostic.POSSIBLE_OBJECT_NAME_OVERFLOW, AnyObject.class, SimpleLoggingKey.POSSIBLE_OBJECT_NAME_OVERFLOW));
logResult.add(logCheckResult(Diagnostic.TABLES_NOT_LINKED_TO_OTHERS, Table.class, SimpleLoggingKey.TABLES_NOT_LINKED_TO_OTHERS));
+ logResult.add(logCheckResult(Diagnostic.FOREIGN_KEYS_WITH_UNMATCHED_COLUMN_TYPE, ForeignKey.class, SimpleLoggingKey.FOREIGN_KEYS_WITH_UNMATCHED_COLUMN_TYPE));
return logResult;
} finally {
databaseChecksHolder.set(null);
diff --git a/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/SimpleLoggingKey.java b/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/SimpleLoggingKey.java
index 3f8a386b..8addf8fa 100644
--- a/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/SimpleLoggingKey.java
+++ b/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/health/logger/SimpleLoggingKey.java
@@ -38,7 +38,8 @@ public enum SimpleLoggingKey implements LoggingKey {
DUPLICATED_FOREIGN_KEYS("duplicated_foreign_keys"),
INTERSECTED_FOREIGN_KEYS("intersected_foreign_keys"),
POSSIBLE_OBJECT_NAME_OVERFLOW("possible_object_name_overflow"),
- TABLES_NOT_LINKED_TO_OTHERS("tables_not_linked_to_others");
+ TABLES_NOT_LINKED_TO_OTHERS("tables_not_linked_to_others"),
+ FOREIGN_KEYS_WITH_UNMATCHED_COLUMN_TYPE("foreign_keys_with_unmatched_column_type");
private final String subKeyName;
diff --git a/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/maintenance/DatabaseChecks.java b/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/maintenance/DatabaseChecks.java
index 4fd07dbf..6b2277e9 100644
--- a/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/maintenance/DatabaseChecks.java
+++ b/pg-index-health-logger/src/main/java/io/github/mfvanek/pg/common/maintenance/DatabaseChecks.java
@@ -17,6 +17,7 @@
import io.github.mfvanek.pg.checks.cluster.DuplicatedForeignKeysCheckOnCluster;
import io.github.mfvanek.pg.checks.cluster.DuplicatedIndexesCheckOnCluster;
import io.github.mfvanek.pg.checks.cluster.ForeignKeysNotCoveredWithIndexCheckOnCluster;
+import io.github.mfvanek.pg.checks.cluster.ForeignKeysWithUnmatchedColumnTypeCheckOnCluster;
import io.github.mfvanek.pg.checks.cluster.FunctionsWithoutDescriptionCheckOnCluster;
import io.github.mfvanek.pg.checks.cluster.IndexesWithBloatCheckOnCluster;
import io.github.mfvanek.pg.checks.cluster.IndexesWithBooleanCheckOnCluster;
@@ -76,7 +77,8 @@ public DatabaseChecks(@Nonnull final HighAvailabilityPgConnection haPgConnection
new DuplicatedForeignKeysCheckOnCluster(haPgConnection),
new IntersectedForeignKeysCheckOnCluster(haPgConnection),
new PossibleObjectNameOverflowCheckOnCluster(haPgConnection),
- new TablesNotLinkedToOthersCheckOnCluster(haPgConnection)
+ new TablesNotLinkedToOthersCheckOnCluster(haPgConnection),
+ new ForeignKeysWithUnmatchedColumnTypeCheckOnCluster(haPgConnection)
);
allChecks.forEach(check -> this.checks.putIfAbsent(check.getDiagnostic(), check));
}
diff --git a/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTest.java b/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTest.java
index 565e6b7c..cdf39dca 100644
--- a/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTest.java
+++ b/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTest.java
@@ -57,7 +57,7 @@ protected String[] getExpectedValue() {
return new String[]{
"1999-12-31T23:59:59Z\tdb_indexes_health\tinvalid_indexes\t1",
"1999-12-31T23:59:59Z\tdb_indexes_health\tduplicated_indexes\t2",
- "1999-12-31T23:59:59Z\tdb_indexes_health\tforeign_keys_without_index\t5",
+ "1999-12-31T23:59:59Z\tdb_indexes_health\tforeign_keys_without_index\t7",
"1999-12-31T23:59:59Z\tdb_indexes_health\ttables_without_primary_key\t2",
"1999-12-31T23:59:59Z\tdb_indexes_health\tindexes_with_null_values\t1",
"1999-12-31T23:59:59Z\tdb_indexes_health\tindexes_with_bloat\t17",
@@ -66,7 +66,7 @@ protected String[] getExpectedValue() {
"1999-12-31T23:59:59Z\tdb_indexes_health\tunused_indexes\t12",
"1999-12-31T23:59:59Z\tdb_indexes_health\ttables_with_missing_indexes\t0",
"1999-12-31T23:59:59Z\tdb_indexes_health\ttables_without_description\t6",
- "1999-12-31T23:59:59Z\tdb_indexes_health\tcolumns_without_description\t25",
+ "1999-12-31T23:59:59Z\tdb_indexes_health\tcolumns_without_description\t27",
"1999-12-31T23:59:59Z\tdb_indexes_health\tcolumns_with_json_type\t1",
"1999-12-31T23:59:59Z\tdb_indexes_health\tcolumns_with_serial_types\t3",
"1999-12-31T23:59:59Z\tdb_indexes_health\tfunctions_without_description\t2",
@@ -78,7 +78,8 @@ protected String[] getExpectedValue() {
"1999-12-31T23:59:59Z\tdb_indexes_health\tduplicated_foreign_keys\t3",
"1999-12-31T23:59:59Z\tdb_indexes_health\tintersected_foreign_keys\t1",
"1999-12-31T23:59:59Z\tdb_indexes_health\tpossible_object_name_overflow\t2",
- "1999-12-31T23:59:59Z\tdb_indexes_health\ttables_not_linked_to_others\t3"
+ "1999-12-31T23:59:59Z\tdb_indexes_health\ttables_not_linked_to_others\t2",
+ "1999-12-31T23:59:59Z\tdb_indexes_health\tforeign_keys_with_unmatched_column_type\t2"
};
}
diff --git a/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTestBase.java b/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTestBase.java
index 6f80a599..d6e248d1 100644
--- a/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTestBase.java
+++ b/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/HealthLoggerTestBase.java
@@ -48,7 +48,8 @@ abstract class HealthLoggerTestBase extends StatisticsAwareTestBase {
.withDuplicatedForeignKeys()
.withIntersectedForeignKeys()
.withMaterializedView()
- .withIdentityPrimaryKey();
+ .withIdentityPrimaryKey()
+ .withForeignKeyOnNullableColumn();
@Nonnull
protected static Predicate ofKey(@Nonnull final LoggingKey key) {
diff --git a/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/StandardHealthLoggerTest.java b/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/StandardHealthLoggerTest.java
index 0ab1f508..37689e1e 100644
--- a/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/StandardHealthLoggerTest.java
+++ b/pg-index-health-logger/src/test/java/io/github/mfvanek/pg/common/health/logger/StandardHealthLoggerTest.java
@@ -28,7 +28,7 @@ protected String[] getExpectedValue() {
return new String[]{
"invalid_indexes:1",
"duplicated_indexes:2",
- "foreign_keys_without_index:5",
+ "foreign_keys_without_index:7",
"tables_without_primary_key:2",
"indexes_with_null_values:1",
"indexes_with_bloat:17",
@@ -37,7 +37,7 @@ protected String[] getExpectedValue() {
"unused_indexes:12",
"tables_with_missing_indexes:0",
"tables_without_description:6",
- "columns_without_description:25",
+ "columns_without_description:27",
"columns_with_json_type:1",
"columns_with_serial_types:3",
"functions_without_description:2",
@@ -49,7 +49,8 @@ protected String[] getExpectedValue() {
"duplicated_foreign_keys:3",
"intersected_foreign_keys:1",
"possible_object_name_overflow:2",
- "tables_not_linked_to_others:3"
+ "tables_not_linked_to_others:2",
+ "foreign_keys_with_unmatched_column_type:2"
};
}
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnTest.java
index 27869343..6fc5e659 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnTest.java
@@ -118,7 +118,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(Column.class)
.verify();
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnWithSerialTypeTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnWithSerialTypeTest.java
index 00d04b6f..8b689526 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnWithSerialTypeTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/column/ColumnWithSerialTypeTest.java
@@ -139,7 +139,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(ColumnWithSerialType.class)
.verify();
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ConstraintTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ConstraintTest.java
index d6392ddd..b0e9639a 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ConstraintTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ConstraintTest.java
@@ -115,7 +115,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(Constraint.class)
.withIgnoredFields("constraintType")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/DuplicatedForeignKeysTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/DuplicatedForeignKeysTest.java
index 784cb55c..652359e6 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/DuplicatedForeignKeysTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/DuplicatedForeignKeysTest.java
@@ -101,7 +101,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(DuplicatedForeignKeys.class)
.withIgnoredFields("foreignKeysNames")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ForeignKeyTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ForeignKeyTest.java
index 3dbe0517..5c0e5bff 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ForeignKeyTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/constraint/ForeignKeyTest.java
@@ -176,7 +176,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(ForeignKey.class)
.withIgnoredFields("constraintType", "columnsInConstraint")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/function/StoredFunctionTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/function/StoredFunctionTest.java
index 7634ad08..534bdcb6 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/function/StoredFunctionTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/function/StoredFunctionTest.java
@@ -123,7 +123,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(StoredFunction.class)
.verify();
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/DuplicatedIndexesTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/DuplicatedIndexesTest.java
index adaad947..7b957986 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/DuplicatedIndexesTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/DuplicatedIndexesTest.java
@@ -190,7 +190,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(DuplicatedIndexes.class)
.withIgnoredFields("totalSize", "indexesNames")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexTest.java
index 9aa4c5f6..63db4fce 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexTest.java
@@ -96,7 +96,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(Index.class)
.verify();
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithBloatTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithBloatTest.java
index 7a915683..530fe8d5 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithBloatTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithBloatTest.java
@@ -99,7 +99,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(IndexWithBloat.class)
.withIgnoredFields("indexSizeInBytes", "bloatSizeInBytes", "bloatPercentage")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithColumnsTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithColumnsTest.java
index fce34a4f..fbbb6bed 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithColumnsTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithColumnsTest.java
@@ -125,7 +125,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(IndexWithColumns.class)
.withIgnoredFields("indexSizeInBytes", "columns")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithNullsTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithNullsTest.java
index c3b70c45..2da757a0 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithNullsTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithNullsTest.java
@@ -111,7 +111,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(IndexWithNulls.class)
.withIgnoredFields("indexSizeInBytes", "columns")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithSizeTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithSizeTest.java
index 808e05cf..4fb9fafa 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithSizeTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/IndexWithSizeTest.java
@@ -90,7 +90,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(IndexWithSize.class)
.withIgnoredFields("indexSizeInBytes")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/UnusedIndexTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/UnusedIndexTest.java
index ba4c57f3..e15b53e0 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/UnusedIndexTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/index/UnusedIndexTest.java
@@ -89,7 +89,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(UnusedIndex.class)
.withIgnoredFields("indexSizeInBytes", "indexScans")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/object/AnyObjectTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/object/AnyObjectTest.java
index 906c750f..2b004444 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/object/AnyObjectTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/object/AnyObjectTest.java
@@ -95,7 +95,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(AnyObject.class)
.verify();
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableTest.java
index 35ee7e6e..594546d3 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableTest.java
@@ -96,7 +96,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(Table.class)
.withIgnoredFields("tableSizeInBytes")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithBloatTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithBloatTest.java
index d1a92536..ea09de56 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithBloatTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithBloatTest.java
@@ -107,7 +107,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(TableWithBloat.class)
.withIgnoredFields("bloatSizeInBytes", "bloatPercentage")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithMissingIndexTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithMissingIndexTest.java
index 93116b45..cb700585 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithMissingIndexTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/model/table/TableWithMissingIndexTest.java
@@ -104,7 +104,6 @@ void testEqualsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(TableWithMissingIndex.class)
.withIgnoredFields("seqScans", "indexScans")
diff --git a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/settings/PgParamImplTest.java b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/settings/PgParamImplTest.java
index 31ac7b4d..17f93fee 100644
--- a/pg-index-health-model/src/test/java/io/github/mfvanek/pg/settings/PgParamImplTest.java
+++ b/pg-index-health-model/src/test/java/io/github/mfvanek/pg/settings/PgParamImplTest.java
@@ -94,7 +94,6 @@ void equalsAndHashCode() {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
void equalsHashCodeShouldAdhereContracts() {
EqualsVerifier.forClass(PgParamImpl.class)
.withIgnoredFields("value")
diff --git a/pg-index-health/src/main/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysWithUnmatchedColumnTypeCheckOnCluster.java b/pg-index-health/src/main/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysWithUnmatchedColumnTypeCheckOnCluster.java
new file mode 100644
index 00000000..8f4800f9
--- /dev/null
+++ b/pg-index-health/src/main/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysWithUnmatchedColumnTypeCheckOnCluster.java
@@ -0,0 +1,36 @@
+/*
+ * 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.checks.cluster;
+
+import io.github.mfvanek.pg.checks.host.ForeignKeysWithUnmatchedColumnTypeCheckOnHost;
+import io.github.mfvanek.pg.connection.HighAvailabilityPgConnection;
+import io.github.mfvanek.pg.model.constraint.ForeignKey;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Check for foreign keys where the type of the constrained column does not match the type in the referenced table on all hosts in the cluster.
+ *
+ * The column types in the referring and target relation must match.
+ * For example, a column with the {@code integer} type should refer to a column with the {@code integer} type.
+ * This eliminates unnecessary conversions at the DBMS level and in the application code,
+ * and reduces the number of errors that may appear due to type inconsistencies in the future.
+ *
+ * @author Ivan Vahrushev
+ * @see pg_constraint
+ * @since 0.13.2
+ */
+public class ForeignKeysWithUnmatchedColumnTypeCheckOnCluster extends AbstractCheckOnCluster {
+
+ public ForeignKeysWithUnmatchedColumnTypeCheckOnCluster(@Nonnull final HighAvailabilityPgConnection haPgConnection) {
+ super(haPgConnection, ForeignKeysWithUnmatchedColumnTypeCheckOnHost::new);
+ }
+}
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysNotCoveredWithIndexCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysNotCoveredWithIndexCheckOnClusterTest.java
index a2393064..09dc3cc2 100644
--- a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysNotCoveredWithIndexCheckOnClusterTest.java
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysNotCoveredWithIndexCheckOnClusterTest.java
@@ -22,6 +22,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
+import java.util.List;
import java.util.function.Predicate;
import static io.github.mfvanek.pg.support.AbstractCheckOnClusterAssert.assertThat;
@@ -51,22 +52,30 @@ void onDatabaseWithoutThem(final String schemaName) {
@ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
void onDatabaseWithThem(final String schemaName) {
executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withForeignKeyOnNullableColumn(), ctx -> {
+ final String accountsTableName = ctx.enrichWithSchema("accounts");
+ final String badClientsTableName = ctx.enrichWithSchema("bad_clients");
assertThat(check)
.executing(ctx)
- .hasSize(2)
+ .hasSize(3)
.containsExactlyInAnyOrder(
- ForeignKey.ofColumn(ctx.enrichWithSchema("accounts"), "c_accounts_fk_client_id",
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id")),
- ForeignKey.ofColumn(ctx.enrichWithSchema("bad_clients"), "c_bad_clients_fk_real_client_id",
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id")))
+ ForeignKey.ofColumn(accountsTableName, "c_accounts_fk_client_id",
+ Column.ofNotNull(accountsTableName, "client_id")),
+ ForeignKey.ofColumn(badClientsTableName, "c_bad_clients_fk_real_client_id",
+ Column.ofNullable(badClientsTableName, "real_client_id")),
+ ForeignKey.of(badClientsTableName, "c_bad_clients_fk_email_phone",
+ List.of(
+ Column.ofNullable(badClientsTableName, "email"),
+ Column.ofNullable(badClientsTableName, "phone"))))
.flatExtracting(ForeignKey::getColumnsInConstraint)
- .hasSize(2)
+ .hasSize(4)
.containsExactlyInAnyOrder(
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id"),
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id"));
+ Column.ofNotNull(accountsTableName, "client_id"),
+ Column.ofNullable(badClientsTableName, "real_client_id"),
+ Column.ofNullable(badClientsTableName, "email"),
+ Column.ofNullable(badClientsTableName, "phone"));
- final Predicate predicate = FilterTablesByNamePredicate.of(ctx.enrichWithSchema("accounts"))
- .and(FilterTablesByNamePredicate.of(ctx.enrichWithSchema("bad_clients")));
+ final Predicate predicate = FilterTablesByNamePredicate.of(accountsTableName)
+ .and(FilterTablesByNamePredicate.of(badClientsTableName));
assertThat(check)
.executing(ctx, predicate)
.isEmpty();
@@ -76,25 +85,17 @@ void onDatabaseWithThem(final String schemaName) {
@ParameterizedTest
@ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
void onDatabaseWithNotSuitableIndex(final String schemaName) {
- executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withForeignKeyOnNullableColumn().withNonSuitableIndex(), ctx -> {
+ executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withNonSuitableIndex(), ctx -> {
+ final String accountsTableName = ctx.enrichWithSchema("accounts");
assertThat(check)
.executing(ctx)
- .hasSize(2)
- .containsExactlyInAnyOrder(
- ForeignKey.ofColumn(ctx.enrichWithSchema("accounts"), "c_accounts_fk_client_id",
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id")),
- ForeignKey.ofColumn(ctx.enrichWithSchema("bad_clients"), "c_bad_clients_fk_real_client_id",
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id")))
- .flatExtracting(ForeignKey::getColumnsInConstraint)
- .hasSize(2)
- .containsExactlyInAnyOrder(
- Column.ofNotNull(ctx.enrichWithSchema("accounts"), "client_id"),
- Column.ofNullable(ctx.enrichWithSchema("bad_clients"), "real_client_id"));
+ .hasSize(1)
+ .containsExactly(
+ ForeignKey.ofColumn(accountsTableName, "c_accounts_fk_client_id",
+ Column.ofNotNull(accountsTableName, "client_id")));
- final Predicate predicate = FilterTablesByNamePredicate.of(ctx.enrichWithSchema("accounts"))
- .and(FilterTablesByNamePredicate.of(ctx.enrichWithSchema("bad_clients")));
assertThat(check)
- .executing(ctx, predicate)
+ .executing(ctx, FilterTablesByNamePredicate.of(accountsTableName))
.isEmpty();
});
}
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysWithUnmatchedColumnTypeCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysWithUnmatchedColumnTypeCheckOnClusterTest.java
new file mode 100644
index 00000000..c34da7e4
--- /dev/null
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/ForeignKeysWithUnmatchedColumnTypeCheckOnClusterTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.checks.cluster;
+
+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.constraint.ForeignKey;
+import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static io.github.mfvanek.pg.support.AbstractCheckOnClusterAssert.assertThat;
+
+class ForeignKeysWithUnmatchedColumnTypeCheckOnClusterTest extends DatabaseAwareTestBase {
+
+ private final DatabaseCheckOnCluster check = new ForeignKeysWithUnmatchedColumnTypeCheckOnCluster(getHaPgConnection());
+
+ @Test
+ void shouldSatisfyContract() {
+ assertThat(check)
+ .hasType(ForeignKey.class)
+ .hasDiagnostic(Diagnostic.FOREIGN_KEYS_WITH_UNMATCHED_COLUMN_TYPE)
+ .isStatic();
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
+ void onDatabaseWithThem(final String schemaName) {
+ executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withForeignKeyOnNullableColumn(), ctx -> {
+ final String badClientsTableName = ctx.enrichWithSchema("bad_clients");
+ assertThat(check)
+ .executing(ctx)
+ .hasSize(2)
+ .containsExactlyInAnyOrder(
+ ForeignKey.ofColumn(badClientsTableName, "c_bad_clients_fk_real_client_id",
+ Column.ofNullable(badClientsTableName, "real_client_id")),
+ ForeignKey.ofColumn(badClientsTableName, "c_bad_clients_fk_email_phone",
+ Column.ofNullable(badClientsTableName, "phone"))
+ );
+ });
+ }
+}
diff --git a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/TablesWithoutPrimaryKeyCheckOnClusterTest.java b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/TablesWithoutPrimaryKeyCheckOnClusterTest.java
index be389458..c84d0655 100644
--- a/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/TablesWithoutPrimaryKeyCheckOnClusterTest.java
+++ b/pg-index-health/src/test/java/io/github/mfvanek/pg/checks/cluster/TablesWithoutPrimaryKeyCheckOnClusterTest.java
@@ -41,8 +41,7 @@ void onDatabaseWithThem(final String schemaName) {
assertThat(check)
.executing(ctx)
.hasSize(1)
- .containsExactly(Table.of(ctx.enrichWithSchema("bad_clients"), 0L))
- .allMatch(t -> t.getTableSizeInBytes() == 0L);
+ .containsExactly(Table.of(ctx.enrichWithSchema("bad_clients"), 0L));
assertThat(check)
.executing(ctx, FilterTablesByNamePredicate.of(ctx.enrichWithSchema("bad_clients")))
diff --git a/spring-boot-integration/pg-index-health-test-starter/src/main/java/io/github/mfvanek/pg/spring/DatabaseStructureChecksAutoConfiguration.java b/spring-boot-integration/pg-index-health-test-starter/src/main/java/io/github/mfvanek/pg/spring/DatabaseStructureChecksAutoConfiguration.java
new file mode 100644
index 00000000..def6dc21
--- /dev/null
+++ b/spring-boot-integration/pg-index-health-test-starter/src/main/java/io/github/mfvanek/pg/spring/DatabaseStructureChecksAutoConfiguration.java
@@ -0,0 +1,248 @@
+/*
+ * 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.spring;
+
+import io.github.mfvanek.pg.checks.host.BtreeIndexesOnArrayColumnsCheckOnHost;
+import io.github.mfvanek.pg.checks.host.ColumnsWithJsonTypeCheckOnHost;
+import io.github.mfvanek.pg.checks.host.ColumnsWithSerialTypesCheckOnHost;
+import io.github.mfvanek.pg.checks.host.ColumnsWithoutDescriptionCheckOnHost;
+import io.github.mfvanek.pg.checks.host.DuplicatedForeignKeysCheckOnHost;
+import io.github.mfvanek.pg.checks.host.DuplicatedIndexesCheckOnHost;
+import io.github.mfvanek.pg.checks.host.ForeignKeysNotCoveredWithIndexCheckOnHost;
+import io.github.mfvanek.pg.checks.host.ForeignKeysWithUnmatchedColumnTypeCheckOnHost;
+import io.github.mfvanek.pg.checks.host.FunctionsWithoutDescriptionCheckOnHost;
+import io.github.mfvanek.pg.checks.host.IndexesWithBloatCheckOnHost;
+import io.github.mfvanek.pg.checks.host.IndexesWithBooleanCheckOnHost;
+import io.github.mfvanek.pg.checks.host.IndexesWithNullValuesCheckOnHost;
+import io.github.mfvanek.pg.checks.host.IntersectedForeignKeysCheckOnHost;
+import io.github.mfvanek.pg.checks.host.IntersectedIndexesCheckOnHost;
+import io.github.mfvanek.pg.checks.host.InvalidIndexesCheckOnHost;
+import io.github.mfvanek.pg.checks.host.NotValidConstraintsCheckOnHost;
+import io.github.mfvanek.pg.checks.host.PossibleObjectNameOverflowCheckOnHost;
+import io.github.mfvanek.pg.checks.host.PrimaryKeysWithSerialTypesCheckOnHost;
+import io.github.mfvanek.pg.checks.host.SequenceOverflowCheckOnHost;
+import io.github.mfvanek.pg.checks.host.TablesNotLinkedToOthersCheckOnHost;
+import io.github.mfvanek.pg.checks.host.TablesWithBloatCheckOnHost;
+import io.github.mfvanek.pg.checks.host.TablesWithMissingIndexesCheckOnHost;
+import io.github.mfvanek.pg.checks.host.TablesWithoutDescriptionCheckOnHost;
+import io.github.mfvanek.pg.checks.host.TablesWithoutPrimaryKeyCheckOnHost;
+import io.github.mfvanek.pg.checks.host.UnusedIndexesCheckOnHost;
+import io.github.mfvanek.pg.connection.PgConnection;
+import io.github.mfvanek.pg.settings.maintenance.ConfigurationMaintenanceOnHost;
+import io.github.mfvanek.pg.settings.maintenance.ConfigurationMaintenanceOnHostImpl;
+import io.github.mfvanek.pg.statistics.maintenance.StatisticsMaintenanceOnHost;
+import io.github.mfvanek.pg.statistics.maintenance.StatisticsMaintenanceOnHostImpl;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Autoconfiguration for database checks.
+ *
+ * @author Ivan Vakhrushev
+ * @since 0.13.2
+ */
+@SuppressWarnings({"checkstyle:ClassDataAbstractionCoupling", "checkstyle:ClassFanOutComplexity"})
+@AutoConfiguration(after = DatabaseStructureHealthAutoConfiguration.class)
+@ConditionalOnBean(PgConnection.class)
+public class DatabaseStructureChecksAutoConfiguration {
+
+ @Bean
+ @ConditionalOnClass(DuplicatedIndexesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public DuplicatedIndexesCheckOnHost duplicatedIndexesCheckOnHost(final PgConnection pgConnection) {
+ return new DuplicatedIndexesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(ForeignKeysNotCoveredWithIndexCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public ForeignKeysNotCoveredWithIndexCheckOnHost foreignKeysNotCoveredWithIndexCheckOnHost(final PgConnection pgConnection) {
+ return new ForeignKeysNotCoveredWithIndexCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(IndexesWithBloatCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public IndexesWithBloatCheckOnHost indexesWithBloatCheckOnHost(final PgConnection pgConnection) {
+ return new IndexesWithBloatCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(IndexesWithNullValuesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public IndexesWithNullValuesCheckOnHost indexesWithNullValuesCheckOnHost(final PgConnection pgConnection) {
+ return new IndexesWithNullValuesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(IntersectedIndexesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public IntersectedIndexesCheckOnHost intersectedIndexesCheckOnHost(final PgConnection pgConnection) {
+ return new IntersectedIndexesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(InvalidIndexesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public InvalidIndexesCheckOnHost invalidIndexesCheckOnHost(final PgConnection pgConnection) {
+ return new InvalidIndexesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(TablesWithBloatCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public TablesWithBloatCheckOnHost tablesWithBloatCheckOnHost(final PgConnection pgConnection) {
+ return new TablesWithBloatCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(TablesWithMissingIndexesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public TablesWithMissingIndexesCheckOnHost tablesWithMissingIndexesCheckOnHost(final PgConnection pgConnection) {
+ return new TablesWithMissingIndexesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(TablesWithoutPrimaryKeyCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public TablesWithoutPrimaryKeyCheckOnHost tablesWithoutPrimaryKeyCheckOnHost(final PgConnection pgConnection) {
+ return new TablesWithoutPrimaryKeyCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(UnusedIndexesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public UnusedIndexesCheckOnHost unusedIndexesCheckOnHost(final PgConnection pgConnection) {
+ return new UnusedIndexesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(TablesWithoutDescriptionCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public TablesWithoutDescriptionCheckOnHost tablesWithoutDescriptionCheckOnHost(final PgConnection pgConnection) {
+ return new TablesWithoutDescriptionCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(ColumnsWithoutDescriptionCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public ColumnsWithoutDescriptionCheckOnHost columnsWithoutDescriptionCheckOnHost(final PgConnection pgConnection) {
+ return new ColumnsWithoutDescriptionCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(ColumnsWithJsonTypeCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public ColumnsWithJsonTypeCheckOnHost columnsWithJsonTypeCheckOnHost(final PgConnection pgConnection) {
+ return new ColumnsWithJsonTypeCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(ColumnsWithSerialTypesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public ColumnsWithSerialTypesCheckOnHost columnsWithSerialTypesCheckOnHost(final PgConnection pgConnection) {
+ return new ColumnsWithSerialTypesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(FunctionsWithoutDescriptionCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public FunctionsWithoutDescriptionCheckOnHost functionsWithoutDescriptionCheckOnHost(final PgConnection pgConnection) {
+ return new FunctionsWithoutDescriptionCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(IndexesWithBooleanCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public IndexesWithBooleanCheckOnHost indexesWithBooleanCheckOnHost(final PgConnection pgConnection) {
+ return new IndexesWithBooleanCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(NotValidConstraintsCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public NotValidConstraintsCheckOnHost notValidConstraintsCheckOnHost(final PgConnection pgConnection) {
+ return new NotValidConstraintsCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(BtreeIndexesOnArrayColumnsCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public BtreeIndexesOnArrayColumnsCheckOnHost btreeIndexesOnArrayColumnsCheckOnHost(final PgConnection pgConnection) {
+ return new BtreeIndexesOnArrayColumnsCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(SequenceOverflowCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public SequenceOverflowCheckOnHost sequenceOverflowCheckOnHost(final PgConnection pgConnection) {
+ return new SequenceOverflowCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(PrimaryKeysWithSerialTypesCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public PrimaryKeysWithSerialTypesCheckOnHost primaryKeysWithSerialTypesCheckOnHost(final PgConnection pgConnection) {
+ return new PrimaryKeysWithSerialTypesCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(DuplicatedForeignKeysCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public DuplicatedForeignKeysCheckOnHost duplicatedForeignKeysCheckOnHost(final PgConnection pgConnection) {
+ return new DuplicatedForeignKeysCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(IntersectedForeignKeysCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public IntersectedForeignKeysCheckOnHost intersectedForeignKeysCheckOnHost(final PgConnection pgConnection) {
+ return new IntersectedForeignKeysCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(PossibleObjectNameOverflowCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public PossibleObjectNameOverflowCheckOnHost possibleObjectNameOverflowCheckOnHost(final PgConnection pgConnection) {
+ return new PossibleObjectNameOverflowCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(TablesNotLinkedToOthersCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public TablesNotLinkedToOthersCheckOnHost tablesNotLinkedToOthersCheckOnHost(final PgConnection pgConnection) {
+ return new TablesNotLinkedToOthersCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(ForeignKeysWithUnmatchedColumnTypeCheckOnHost.class)
+ @ConditionalOnMissingBean
+ public ForeignKeysWithUnmatchedColumnTypeCheckOnHost foreignKeysWithUnmatchedColumnTypeCheckOnHost(final PgConnection pgConnection) {
+ return new ForeignKeysWithUnmatchedColumnTypeCheckOnHost(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(StatisticsMaintenanceOnHost.class)
+ @ConditionalOnMissingBean
+ public StatisticsMaintenanceOnHost statisticsMaintenanceOnHost(final PgConnection pgConnection) {
+ return new StatisticsMaintenanceOnHostImpl(pgConnection);
+ }
+
+ @Bean
+ @ConditionalOnClass(ConfigurationMaintenanceOnHost.class)
+ @ConditionalOnMissingBean
+ public ConfigurationMaintenanceOnHost configurationMaintenanceOnHost(final PgConnection pgConnection) {
+ return new ConfigurationMaintenanceOnHostImpl(pgConnection);
+ }
+}
diff --git a/spring-boot-integration/pg-index-health-test-starter/src/main/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfiguration.java b/spring-boot-integration/pg-index-health-test-starter/src/main/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfiguration.java
index c518f468..ba92f04d 100644
--- a/spring-boot-integration/pg-index-health-test-starter/src/main/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfiguration.java
+++ b/spring-boot-integration/pg-index-health-test-starter/src/main/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfiguration.java
@@ -10,43 +10,14 @@
package io.github.mfvanek.pg.spring;
-import io.github.mfvanek.pg.checks.host.BtreeIndexesOnArrayColumnsCheckOnHost;
-import io.github.mfvanek.pg.checks.host.ColumnsWithJsonTypeCheckOnHost;
-import io.github.mfvanek.pg.checks.host.ColumnsWithSerialTypesCheckOnHost;
-import io.github.mfvanek.pg.checks.host.ColumnsWithoutDescriptionCheckOnHost;
-import io.github.mfvanek.pg.checks.host.DuplicatedForeignKeysCheckOnHost;
-import io.github.mfvanek.pg.checks.host.DuplicatedIndexesCheckOnHost;
-import io.github.mfvanek.pg.checks.host.ForeignKeysNotCoveredWithIndexCheckOnHost;
-import io.github.mfvanek.pg.checks.host.FunctionsWithoutDescriptionCheckOnHost;
-import io.github.mfvanek.pg.checks.host.IndexesWithBloatCheckOnHost;
-import io.github.mfvanek.pg.checks.host.IndexesWithBooleanCheckOnHost;
-import io.github.mfvanek.pg.checks.host.IndexesWithNullValuesCheckOnHost;
-import io.github.mfvanek.pg.checks.host.IntersectedForeignKeysCheckOnHost;
-import io.github.mfvanek.pg.checks.host.IntersectedIndexesCheckOnHost;
-import io.github.mfvanek.pg.checks.host.InvalidIndexesCheckOnHost;
-import io.github.mfvanek.pg.checks.host.NotValidConstraintsCheckOnHost;
-import io.github.mfvanek.pg.checks.host.PossibleObjectNameOverflowCheckOnHost;
-import io.github.mfvanek.pg.checks.host.PrimaryKeysWithSerialTypesCheckOnHost;
-import io.github.mfvanek.pg.checks.host.SequenceOverflowCheckOnHost;
-import io.github.mfvanek.pg.checks.host.TablesNotLinkedToOthersCheckOnHost;
-import io.github.mfvanek.pg.checks.host.TablesWithBloatCheckOnHost;
-import io.github.mfvanek.pg.checks.host.TablesWithMissingIndexesCheckOnHost;
-import io.github.mfvanek.pg.checks.host.TablesWithoutDescriptionCheckOnHost;
-import io.github.mfvanek.pg.checks.host.TablesWithoutPrimaryKeyCheckOnHost;
-import io.github.mfvanek.pg.checks.host.UnusedIndexesCheckOnHost;
import io.github.mfvanek.pg.connection.PgConnection;
import io.github.mfvanek.pg.connection.PgConnectionImpl;
import io.github.mfvanek.pg.connection.PgHost;
import io.github.mfvanek.pg.connection.PgHostImpl;
import io.github.mfvanek.pg.connection.PgSqlException;
-import io.github.mfvanek.pg.settings.maintenance.ConfigurationMaintenanceOnHost;
-import io.github.mfvanek.pg.settings.maintenance.ConfigurationMaintenanceOnHostImpl;
-import io.github.mfvanek.pg.statistics.maintenance.StatisticsMaintenanceOnHost;
-import io.github.mfvanek.pg.statistics.maintenance.StatisticsMaintenanceOnHostImpl;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -67,13 +38,11 @@
* @author Ivan Vakhrushev
* @since 0.3.1
*/
-@SuppressWarnings({"checkstyle:ClassDataAbstractionCoupling", "checkstyle:ClassFanOutComplexity"})
-@AutoConfiguration
+@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(DatabaseStructureHealthProperties.class)
@ConditionalOnClass(value = DataSource.class, name = "org.postgresql.Driver")
@Conditional(DatabaseStructureHealthCondition.class)
@ConditionalOnProperty(name = "pg.index.health.test.enabled", matchIfMissing = true, havingValue = "true")
-@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class DatabaseStructureHealthAutoConfiguration {
/**
@@ -100,212 +69,4 @@ public PgConnection pgConnection(@Qualifier("dataSource") final DataSource dataS
}
return PgConnectionImpl.of(dataSource, host);
}
-
- @Bean
- @ConditionalOnClass(DuplicatedIndexesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public DuplicatedIndexesCheckOnHost duplicatedIndexesCheckOnHost(final PgConnection pgConnection) {
- return new DuplicatedIndexesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(ForeignKeysNotCoveredWithIndexCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public ForeignKeysNotCoveredWithIndexCheckOnHost foreignKeysNotCoveredWithIndexCheckOnHost(final PgConnection pgConnection) {
- return new ForeignKeysNotCoveredWithIndexCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(IndexesWithBloatCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public IndexesWithBloatCheckOnHost indexesWithBloatCheckOnHost(final PgConnection pgConnection) {
- return new IndexesWithBloatCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(IndexesWithNullValuesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public IndexesWithNullValuesCheckOnHost indexesWithNullValuesCheckOnHost(final PgConnection pgConnection) {
- return new IndexesWithNullValuesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(IntersectedIndexesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public IntersectedIndexesCheckOnHost intersectedIndexesCheckOnHost(final PgConnection pgConnection) {
- return new IntersectedIndexesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(InvalidIndexesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public InvalidIndexesCheckOnHost invalidIndexesCheckOnHost(final PgConnection pgConnection) {
- return new InvalidIndexesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(TablesWithBloatCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public TablesWithBloatCheckOnHost tablesWithBloatCheckOnHost(final PgConnection pgConnection) {
- return new TablesWithBloatCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(TablesWithMissingIndexesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public TablesWithMissingIndexesCheckOnHost tablesWithMissingIndexesCheckOnHost(final PgConnection pgConnection) {
- return new TablesWithMissingIndexesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(TablesWithoutPrimaryKeyCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public TablesWithoutPrimaryKeyCheckOnHost tablesWithoutPrimaryKeyCheckOnHost(final PgConnection pgConnection) {
- return new TablesWithoutPrimaryKeyCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(UnusedIndexesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public UnusedIndexesCheckOnHost unusedIndexesCheckOnHost(final PgConnection pgConnection) {
- return new UnusedIndexesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(TablesWithoutDescriptionCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public TablesWithoutDescriptionCheckOnHost tablesWithoutDescriptionCheckOnHost(final PgConnection pgConnection) {
- return new TablesWithoutDescriptionCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(ColumnsWithoutDescriptionCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public ColumnsWithoutDescriptionCheckOnHost columnsWithoutDescriptionCheckOnHost(final PgConnection pgConnection) {
- return new ColumnsWithoutDescriptionCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(ColumnsWithJsonTypeCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public ColumnsWithJsonTypeCheckOnHost columnsWithJsonTypeCheckOnHost(final PgConnection pgConnection) {
- return new ColumnsWithJsonTypeCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(ColumnsWithSerialTypesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public ColumnsWithSerialTypesCheckOnHost columnsWithSerialTypesCheckOnHost(final PgConnection pgConnection) {
- return new ColumnsWithSerialTypesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(FunctionsWithoutDescriptionCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public FunctionsWithoutDescriptionCheckOnHost functionsWithoutDescriptionCheckOnHost(final PgConnection pgConnection) {
- return new FunctionsWithoutDescriptionCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(IndexesWithBooleanCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public IndexesWithBooleanCheckOnHost indexesWithBooleanCheckOnHost(final PgConnection pgConnection) {
- return new IndexesWithBooleanCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(NotValidConstraintsCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public NotValidConstraintsCheckOnHost notValidConstraintsCheckOnHost(final PgConnection pgConnection) {
- return new NotValidConstraintsCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(BtreeIndexesOnArrayColumnsCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public BtreeIndexesOnArrayColumnsCheckOnHost btreeIndexesOnArrayColumnsCheckOnHost(final PgConnection pgConnection) {
- return new BtreeIndexesOnArrayColumnsCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(SequenceOverflowCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public SequenceOverflowCheckOnHost sequenceOverflowCheckOnHost(final PgConnection pgConnection) {
- return new SequenceOverflowCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(PrimaryKeysWithSerialTypesCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public PrimaryKeysWithSerialTypesCheckOnHost primaryKeysWithSerialTypesCheckOnHost(final PgConnection pgConnection) {
- return new PrimaryKeysWithSerialTypesCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(DuplicatedForeignKeysCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public DuplicatedForeignKeysCheckOnHost duplicatedForeignKeysCheckOnHost(final PgConnection pgConnection) {
- return new DuplicatedForeignKeysCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(IntersectedForeignKeysCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public IntersectedForeignKeysCheckOnHost intersectedForeignKeysCheckOnHost(final PgConnection pgConnection) {
- return new IntersectedForeignKeysCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(PossibleObjectNameOverflowCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public PossibleObjectNameOverflowCheckOnHost possibleObjectNameOverflowCheckOnHost(final PgConnection pgConnection) {
- return new PossibleObjectNameOverflowCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(TablesNotLinkedToOthersCheckOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public TablesNotLinkedToOthersCheckOnHost tablesNotLinkedToOthersCheckOnHost(final PgConnection pgConnection) {
- return new TablesNotLinkedToOthersCheckOnHost(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(StatisticsMaintenanceOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public StatisticsMaintenanceOnHost statisticsMaintenanceOnHost(final PgConnection pgConnection) {
- return new StatisticsMaintenanceOnHostImpl(pgConnection);
- }
-
- @Bean
- @ConditionalOnClass(ConfigurationMaintenanceOnHost.class)
- @ConditionalOnBean(PgConnection.class)
- @ConditionalOnMissingBean
- public ConfigurationMaintenanceOnHost configurationMaintenanceOnHost(final PgConnection pgConnection) {
- return new ConfigurationMaintenanceOnHostImpl(pgConnection);
- }
}
diff --git a/spring-boot-integration/pg-index-health-test-starter/src/main/resources/META-INF/spring.factories b/spring-boot-integration/pg-index-health-test-starter/src/main/resources/META-INF/spring.factories
deleted file mode 100644
index f44d1052..00000000
--- a/spring-boot-integration/pg-index-health-test-starter/src/main/resources/META-INF/spring.factories
+++ /dev/null
@@ -1 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.github.mfvanek.pg.spring.DatabaseStructureHealthAutoConfiguration
diff --git a/spring-boot-integration/pg-index-health-test-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-integration/pg-index-health-test-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index ba8a654e..7e6abb9c 100644
--- a/spring-boot-integration/pg-index-health-test-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/spring-boot-integration/pg-index-health-test-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1 +1,2 @@
io.github.mfvanek.pg.spring.DatabaseStructureHealthAutoConfiguration
+io.github.mfvanek.pg.spring.DatabaseStructureChecksAutoConfiguration
diff --git a/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/AutoConfigurationTestBase.java b/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/AutoConfigurationTestBase.java
index f9e35839..5a82f8a9 100644
--- a/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/AutoConfigurationTestBase.java
+++ b/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/AutoConfigurationTestBase.java
@@ -56,7 +56,8 @@ abstract class AutoConfigurationTestBase {
"duplicatedForeignKeysCheckOnHost",
"intersectedForeignKeysCheckOnHost",
"possibleObjectNameOverflowCheckOnHost",
- "tablesNotLinkedToOthersCheckOnHost"
+ "tablesNotLinkedToOthersCheckOnHost",
+ "foreignKeysWithUnmatchedColumnTypeCheckOnHost"
);
protected static final Class>[] EXPECTED_TYPES = {PgConnection.class, DatabaseCheckOnHost.class, StatisticsMaintenanceOnHost.class, ConfigurationMaintenanceOnHost.class};
protected static final DataSource DATA_SOURCE_MOCK = Mockito.mock(DataSource.class);
@@ -67,7 +68,7 @@ abstract class AutoConfigurationTestBase {
@Nonnull
protected ApplicationContextRunner assertWithTestConfig() {
- return contextRunner.withUserConfiguration(DatabaseStructureHealthAutoConfiguration.class);
+ return contextRunner.withUserConfiguration(DatabaseStructureHealthAutoConfiguration.class, DatabaseStructureChecksAutoConfiguration.class);
}
protected static void initialize(@Nonnull final C applicationContext) {
diff --git a/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfigurationFilteringTest.java b/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfigurationFilteringTest.java
index 51642a18..9e45597f 100644
--- a/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfigurationFilteringTest.java
+++ b/spring-boot-integration/pg-index-health-test-starter/src/test/java/io/github/mfvanek/pg/spring/DatabaseStructureHealthAutoConfigurationFilteringTest.java
@@ -17,6 +17,7 @@
import io.github.mfvanek.pg.checks.host.DuplicatedForeignKeysCheckOnHost;
import io.github.mfvanek.pg.checks.host.DuplicatedIndexesCheckOnHost;
import io.github.mfvanek.pg.checks.host.ForeignKeysNotCoveredWithIndexCheckOnHost;
+import io.github.mfvanek.pg.checks.host.ForeignKeysWithUnmatchedColumnTypeCheckOnHost;
import io.github.mfvanek.pg.checks.host.FunctionsWithoutDescriptionCheckOnHost;
import io.github.mfvanek.pg.checks.host.IndexesWithBloatCheckOnHost;
import io.github.mfvanek.pg.checks.host.IndexesWithBooleanCheckOnHost;
@@ -122,7 +123,8 @@ private static List> getCheckTypes() {
DuplicatedForeignKeysCheckOnHost.class,
IntersectedForeignKeysCheckOnHost.class,
PossibleObjectNameOverflowCheckOnHost.class,
- TablesNotLinkedToOthersCheckOnHost.class
+ TablesNotLinkedToOthersCheckOnHost.class,
+ ForeignKeysWithUnmatchedColumnTypeCheckOnHost.class
);
}
}