package liquibase.diff.output.report; import liquibase.database.Database; import liquibase.diff.Difference; import liquibase.diff.ObjectDifferences; import liquibase.diff.compare.CompareControl; import liquibase.structure.DatabaseObject; import liquibase.diff.DiffResult; import liquibase.diff.StringDiff; import liquibase.exception.DatabaseException; import liquibase.structure.DatabaseObjectComparator; import liquibase.structure.core.Schema; import liquibase.util.StringUtils; import java.io.PrintStream; import java.util.*; public class DiffToReport { private DiffResult diffResult; private PrintStream out; public DiffToReport(DiffResult diffResult, PrintStream out) { this.diffResult = diffResult; this.out = out; } public void print() throws DatabaseException { final DatabaseObjectComparator comparator = new DatabaseObjectComparator(); out.println("Reference Database: " + diffResult.getReferenceSnapshot().getDatabase()); out.println("Comparison Database: " + diffResult.getComparisonSnapshot().getDatabase()); CompareControl.SchemaComparison[] schemas = diffResult.getCompareControl().getSchemaComparisons(); if (schemas != null && schemas.length > 0) { out.println("Compared Schemas: " + StringUtils.join(Arrays.asList(schemas), ", ", new StringUtils.StringUtilsFormatter<CompareControl.SchemaComparison>() { @Override public String toString(CompareControl.SchemaComparison obj) { String referenceName; String comparisonName; Database referenceDatabase = diffResult.getReferenceSnapshot().getDatabase(); Database comparisonDatabase = diffResult.getComparisonSnapshot().getDatabase(); if (referenceDatabase.supportsSchemas()) { referenceName = obj.getReferenceSchema().getSchemaName(); if (referenceName == null) { referenceName = referenceDatabase.getDefaultSchemaName(); } } else if (referenceDatabase.supportsCatalogs()) { referenceName = obj.getReferenceSchema().getCatalogName(); if (referenceName == null) { referenceName = referenceDatabase.getDefaultCatalogName(); } } else { return ""; } if (comparisonDatabase.supportsSchemas()) { comparisonName = obj.getComparisonSchema().getSchemaName(); if (comparisonName == null) { comparisonName = comparisonDatabase.getDefaultSchemaName(); } } else if (comparisonDatabase.supportsCatalogs()) { comparisonName = obj.getComparisonSchema().getCatalogName(); if (comparisonName == null) { comparisonName = comparisonDatabase.getDefaultCatalogName(); } } else { return ""; } if (referenceName == null) { referenceName = StringUtils.trimToEmpty(referenceDatabase.getDefaultSchemaName()); } if (comparisonName == null) { comparisonName = StringUtils.trimToEmpty(comparisonDatabase.getDefaultSchemaName()); } if (referenceName.equalsIgnoreCase(comparisonName)) { return referenceName; } else { return referenceName + " -> " + comparisonName; } } }, true)); } printComparison("Product Name", diffResult.getProductNameDiff(), out); printComparison("Product Version", diffResult.getProductVersionDiff(), out); TreeSet<Class<? extends DatabaseObject>> types = new TreeSet<Class<? extends DatabaseObject>>(new Comparator<Class<? extends DatabaseObject>>() { @Override public int compare(Class<? extends DatabaseObject> o1, Class<? extends DatabaseObject> o2) { return o1.getSimpleName().compareTo(o2.getSimpleName()); } }); types.addAll(diffResult.getCompareControl().getComparedTypes()); for (Class<? extends DatabaseObject> type : types) { if (type.equals(Schema.class) && !diffResult.getComparisonSnapshot().getDatabase().supportsSchemas()) { continue; } printSetComparison("Missing " + getTypeName(type), diffResult.getMissingObjects(type, comparator), out); printSetComparison("Unexpected " + getTypeName(type), diffResult.getUnexpectedObjects(type, comparator), out); printChangedComparison("Changed " + getTypeName(type), diffResult.getChangedObjects(type, comparator), out); } // printColumnComparison(diffResult.getColumns().getChanged(), out); } protected String getTypeName(Class<? extends DatabaseObject> type) { return type.getSimpleName().replaceAll("([A-Z])", " $1").trim() + "(s)"; } protected boolean getIncludeSchema() { return diffResult.getCompareControl().getSchemaComparisons().length > 1; } protected void printChangedComparison(String title, Map<? extends DatabaseObject, ObjectDifferences> objects, PrintStream out) { out.print(title + ": "); if (objects.size() == 0) { out.println("NONE"); } else { out.println(); for (Map.Entry<? extends DatabaseObject, ObjectDifferences> object : objects.entrySet()) { if (object.getValue().hasDifferences()) { out.println(" " + object.getKey()); for (Difference difference : object.getValue().getDifferences()) { out.println(" " + difference.toString()); } } } } } protected void printSetComparison(String title, Set<? extends DatabaseObject> objects, PrintStream out) { out.print(title + ": "); Schema lastSchema = null; if (objects.size() == 0) { out.println("NONE"); } else { out.println(); for (DatabaseObject object : objects) { if (getIncludeSchema() && object.getSchema() != null && (lastSchema == null || !lastSchema.equals(object.getSchema()))) { lastSchema = object.getSchema(); String schemaName = object.getSchema().getName(); if (schemaName == null) { schemaName = object.getSchema().getCatalogName(); } schemaName = includeSchemaComparison(schemaName); out.println(" SCHEMA: " + schemaName); } out.println(" " + object); } } } protected String includeSchemaComparison(String schemaName) { String convertedSchemaName = CompareControl.SchemaComparison.convertSchema(schemaName, diffResult.getCompareControl().getSchemaComparisons()); if (convertedSchemaName != null && !convertedSchemaName.equals(schemaName)) { schemaName = schemaName + " -> " + convertedSchemaName; } return schemaName; } // private void printColumnComparison(SortedSet<Column> changedColumns, // PrintStream out) { // out.print("Changed Columns: "); // if (changedColumns.size() == 0) { // out.println("NONE"); // } else { // out.println(); // for (Column column : changedColumns) { // out.println(" " + column); // Column baseColumn = diffResult.getReferenceSnapshot().getColumn(column.getRelation().getSchema(), // column.getRelation().getName(), column.getName()); // if (baseColumn != null) { // if (baseColumn.isDataTypeDifferent(column)) { // out.println(" from " // + baseColumn.getType() // + " to " // + diffResult.getComparisonSnapshot().getColumn(column.getRelation().getSchema(), column.getRelation().getName(), column.getName()).getType()); // } // if (baseColumn.isNullabilityDifferent(column)) { // Boolean nowNullable = diffResult.getComparisonSnapshot().getColumn(column.getRelation().getSchema(), // column.getRelation().getName(), column.getName()) // .isNullable(); // if (nowNullable == null) { // nowNullable = Boolean.TRUE; // } // if (nowNullable) { // out.println(" now nullable"); // } else { // out.println(" now not null"); // } // } // } // } // } // } protected void printComparison(String title, StringDiff string, PrintStream out) { out.print(title + ":"); if (string == null) { out.print("NULL"); return; } if (string.areEqual()) { out.println(" EQUAL"); } else { String referenceVersion = string.getReferenceVersion(); if (referenceVersion == null) { referenceVersion = "NULL"; } else { referenceVersion = "'" + referenceVersion + "'"; } String targetVersion = string.getTargetVersion(); if (targetVersion == null) { targetVersion = "NULL"; } else { targetVersion = "'" + targetVersion + "'"; } out.println(); out.println(" Reference: " + referenceVersion); out.println(" Target: " + targetVersion); } } }