DatabaseAuditExcludes.java
package io.github.databaseaudits.spring.boot.assertion;
import java.util.List;
import java.util.Set;
/**
* Immutable exclusions for the {@link DatabaseAuditAssertions} facade. Every
* field defaults to empty; build with {@link #builder()} or use
* {@link #none()}. The plan exclusions ({@code planRelations},
* {@code planSqlFragments}) apply to all three plan-based audits (join,
* order-by, where); for per-audit exclusions inject the individual
* {@code *AuditAssertion} beans instead.
*/
public class DatabaseAuditExcludes {
private static final DatabaseAuditExcludes NONE = builder().build();
private final Set<String> foreignKeyIndexConstraints;
private final Set<String> foreignKeyNotNullColumns;
private final Set<String> foreignKeyTypeMatchColumns;
private final Set<String> planRelations;
private final List<String> planSqlFragments;
private final Set<String> primaryKeyTables;
private final Set<String> redundantIndexes;
private final Set<String> unconditionalMutationStatements;
private DatabaseAuditExcludes(final Builder builder) {
this.foreignKeyIndexConstraints = builder.foreignKeyIndexConstraints;
this.foreignKeyNotNullColumns = builder.foreignKeyNotNullColumns;
this.foreignKeyTypeMatchColumns = builder.foreignKeyTypeMatchColumns;
this.planRelations = builder.planRelations;
this.planSqlFragments = builder.planSqlFragments;
this.primaryKeyTables = builder.primaryKeyTables;
this.redundantIndexes = builder.redundantIndexes;
this.unconditionalMutationStatements =
builder.unconditionalMutationStatements;
}
/**
* Returns an empty set of exclusions.
*
* @return the empty exclusions.
*/
public static DatabaseAuditExcludes none() {
return NONE;
}
/**
* Returns a new builder whose exclusions all default to empty.
*
* @return the builder.
*/
public static Builder builder() {
return new Builder();
}
Set<String> foreignKeyIndexConstraints() {
return foreignKeyIndexConstraints;
}
Set<String> foreignKeyNotNullColumns() {
return foreignKeyNotNullColumns;
}
Set<String> foreignKeyTypeMatchColumns() {
return foreignKeyTypeMatchColumns;
}
Set<String> planRelations() {
return planRelations;
}
List<String> planSqlFragments() {
return planSqlFragments;
}
Set<String> primaryKeyTables() {
return primaryKeyTables;
}
Set<String> redundantIndexes() {
return redundantIndexes;
}
Set<String> unconditionalMutationStatements() {
return unconditionalMutationStatements;
}
/**
* Builder for {@link DatabaseAuditExcludes}.
*/
public static final class Builder {
private Set<String> foreignKeyIndexConstraints = Set.of();
private Set<String> foreignKeyNotNullColumns = Set.of();
private Set<String> foreignKeyTypeMatchColumns = Set.of();
private Set<String> planRelations = Set.of();
private List<String> planSqlFragments = List.of();
private Set<String> primaryKeyTables = Set.of();
private Set<String> redundantIndexes = Set.of();
private Set<String> unconditionalMutationStatements = Set.of();
/**
* Excludes intentionally-unindexed FK constraints from the foreign-key
* index audit.
*
* @param constraints
* the FK constraint names to exclude.
* @return this builder.
*/
public Builder foreignKeyIndexConstraints(
final Set<String> constraints) {
this.foreignKeyIndexConstraints = constraints;
return this;
}
/**
* Excludes genuinely-optional foreign key columns from the not-null
* audit.
*
* @param columns
* the {@code table.column} names to exclude.
* @return this builder.
*/
public Builder foreignKeyNotNullColumns(final Set<String> columns) {
this.foreignKeyNotNullColumns = columns;
return this;
}
/**
* Excludes deliberate type mismatches from the foreign-key type-match
* audit.
*
* @param columns
* the {@code table.column} names to exclude.
* @return this builder.
*/
public Builder foreignKeyTypeMatchColumns(final Set<String> columns) {
this.foreignKeyTypeMatchColumns = columns;
return this;
}
/**
* Excludes relations from all three plan-based audits (join, order-by,
* where).
*
* @param relations
* the relation names to exclude.
* @return this builder.
*/
public Builder planRelations(final Set<String> relations) {
this.planRelations = relations;
return this;
}
/**
* Excludes statements containing any of these SQL fragments from all
* three plan-based audits.
*
* @param sqlFragments
* the SQL fragments to exclude.
* @return this builder.
*/
public Builder planSqlFragments(final List<String> sqlFragments) {
this.planSqlFragments = sqlFragments;
return this;
}
/**
* Excludes tables from the primary-key presence audit (the Liquibase
* bookkeeping tables are always excluded in addition to these).
*
* @param tables
* the table names to exclude.
* @return this builder.
*/
public Builder primaryKeyTables(final Set<String> tables) {
this.primaryKeyTables = tables;
return this;
}
/**
* Excludes intentional look-alike indexes from the redundant-index
* audit.
*
* @param indexes
* the index names to exclude.
* @return this builder.
*/
public Builder redundantIndexes(final Set<String> indexes) {
this.redundantIndexes = indexes;
return this;
}
/**
* Excludes deliberate full-table statements from the
* unconditional-mutation audit.
*
* @param statements
* the exact statements to exclude.
* @return this builder.
*/
public Builder unconditionalMutationStatements(
final Set<String> statements) {
this.unconditionalMutationStatements = statements;
return this;
}
/**
* Builds the exclusions.
*
* @return the exclusions.
*/
public DatabaseAuditExcludes build() {
return new DatabaseAuditExcludes(this);
}
}
}