Skip to content

Instantly share code, notes, and snippets.

@ben-manes
Last active February 21, 2018 14:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ben-manes/5638489 to your computer and use it in GitHub Desktop.
Save ben-manes/5638489 to your computer and use it in GitHub Desktop.
/**
* A validator to verify that the jOOQ generated tables match the database table metadata.
*
* @author Ben Manes (ben@addepar.com)
*/
final class SchemaValidator {
private static final Logger logger = LoggerFactory.getLogger(SchemaValidator.class);
private final List<Schema> schemas;
private final DSLContext db;
public SchemaValidator(DSLContext db, List<Schema> schemas) {
this.schemas = schemas;
this.db = db;
}
/** Validates that the generated table against the runtime schema. */
public void validate() {
Stopwatch stopwatch = new Stopwatch().start();
Set<Table<?>> generatedTables = getTablesFor(schemas);
Map<String, Table<?>> databaseTables = getTablesByName(db.meta().getTables());
boolean valid = true;
for (Table<?> generatedTable : generatedTables) {
String tableName = getTableName(generatedTable);
Table<?> databaseTable = databaseTables.get(tableName);
valid &= isValid(generatedTable, databaseTable);
}
logger.debug("Validated database table mappings in {}", stopwatch);
if (!valid) {
logger.error("Shutting down due to failing database schema validation");
System.exit(1);
}
}
/** Returns whether the generated table matches the database table. */
private boolean isValid(Table<?> generatedTable, Table<?> databaseTable) {
if (databaseTable == null) {
logger.error("Table {} not found", generatedTable.getName());
return false;
}
NavigableSet<String> generatedMetadata = getFieldMetadata(generatedTable);
NavigableSet<String> databaseMetadata = getFieldMetadata(databaseTable);
if (!generatedMetadata.equals(databaseMetadata)) {
logger.error("Table {} has different field metadata (expected {} but was {})",
generatedTable.getName(), generatedMetadata, databaseMetadata);
return false;
}
return true;
}
/** Retrieves the tables in the jOOQ generated schemas without the schema prefixes in the name. */
private Set<Table<?>> getTablesFor(List<Schema> schemas) {
Set<Table<?>> tables = Sets.newHashSet();
for (Schema schema : schemas) {
for (Table<?> table : schema.getTables()) {
tables.add(table.asTable(getTableName(table)));
}
}
return tables;
}
/** Creates a mapping of the table name to the table instance. */
private Map<String, Table<?>> getTablesByName(Iterable<Table<?>> tables) {
Map<String, Table<?>> tablesByName = Maps.newHashMap();
for (Table<?> table : tables) {
tablesByName.put(getTableName(table), table);
}
return tablesByName;
}
/** Returns a table normalized name for lookups. */
private static String getTableName(Table<?> table) {
return table.getName().toLowerCase();
}
/**
* Retrieves the comparable field metadata from the database table. Currently this is only the
* field names as the data types may use custom converters.
*/
private NavigableSet<String> getFieldMetadata(Table<?> table) {
NavigableSet<String> metadata = Sets.newTreeSet();
for (Field<?> field : table.fieldsRow().fields()) {
metadata.add(field.getName().toLowerCase());
}
return metadata;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment