Compare Schemas Using Diff
Updated: Jan 26, 2024
This example demonstrates how you can use Data Pipeline to modify and compare schemas. This feature lets you know which entities and fields have been added, modified, and removed. This can be useful in auditing schemas for change management and generating database migration code.
Java Code
package com.northconcepts.datapipeline.foundations.examples.schema;
import com.northconcepts.datapipeline.core.FieldType;
import com.northconcepts.datapipeline.foundations.schema.BooleanFieldDef;
import com.northconcepts.datapipeline.foundations.schema.EntityDef;
import com.northconcepts.datapipeline.foundations.schema.NumericFieldDef;
import com.northconcepts.datapipeline.foundations.schema.RecordFieldDef;
import com.northconcepts.datapipeline.foundations.schema.SchemaDef;
import com.northconcepts.datapipeline.foundations.schema.TemporalFieldDef;
import com.northconcepts.datapipeline.foundations.schema.TextFieldDef;
import com.northconcepts.datapipeline.foundations.schema.diff.SchemaDefDiff;
public class CompareSchemas {
public static void main(String[] args) {
SchemaDef oldSchema = new SchemaDef("schema-01");
oldSchema.addEntity(new EntityDef("account")
.addField(new TextFieldDef("name", FieldType.STRING).setRequired(true).setAllowBlank(false).setMaximumLength(100))
.addField(new TextFieldDef("number", FieldType.STRING).setRequired(true).setAllowBlank(false).setMaximumLength(20))
.addField(new NumericFieldDef("balance", FieldType.BIG_DECIMAL).setRequired(true).setMinimum(0).setMaximum(10_000_000)));
oldSchema.addEntity(new EntityDef("customer")
.addField(new TextFieldDef("name", FieldType.STRING).setRequired(true).setAllowBlank(false).setMaximumLength(100))
.addField(new NumericFieldDef("age", FieldType.INT).setRequired(true).setMinimum(25).setMaximum(75))
.addField(new NumericFieldDef("balance", FieldType.BIG_DECIMAL))
.addField(new BooleanFieldDef("active", FieldType.BOOLEAN).setAllowedValues(null))
.addField(new NumericFieldDef("bonuses", FieldType.DOUBLE).setArray(true))
.addField(new NumericFieldDef("balanceAge", FieldType.DOUBLE).setArray(true))
.addField(new TemporalFieldDef("lastUpdated", FieldType.DATE).setPattern("yyyy-MM-dd"))
.addField(new RecordFieldDef("accounts", "account").setRequired(true).setArray(true)));
SchemaDef newSchema = oldSchema.clone();
EntityDef customerEntity = newSchema.getEntity("customer");
// Update property of FieldDef
customerEntity.getField("age").setRequired(false);
// Remove field from customer entity
customerEntity.getFields().remove(customerEntity.indexOfField("balanceAge"));
// Add a new field to cutomer entity
customerEntity.addField(new TemporalFieldDef("created_on", FieldType.DATETIME).setPattern("yyyy-MM-dd HH:mm:ss"));
// Remove account entity
newSchema.getEntities().remove(newSchema.indexOfEntity("account"));
// Add new entity to schema
newSchema.addEntity(new EntityDef("bank")
.addField(new TextFieldDef("bank_name", FieldType.STRING).setRequired(true))
);
SchemaDefDiff diff = SchemaDefDiff.diff(oldSchema, newSchema);
// All of above updates to newSchema are reported as
// 1. CHANGED - if property is just updated.
// 2. ADDED - if a new property is added.
// 3. REMOVED - if an existing property is removed.
// 4. NONE - if there is no change for specific property.
System.out.println("Schema Diff: " + diff);
}
}
Code Walkthrough
- An
oldSchemais created and initialized with two entities (account and customer) containing a variety of fields along with their properties. - A
newSchemais created by cloning theoldSchema. The customer entity in the cloned schema is modified to change, remove, and add new fields. The cloned schema is also modified by removing the account entity and adding a new bank entity. - SchemaDefDiff instance is created by calling
diff()method with two arguments ofoldSchemaandnewSchema. - All of the above updates to
newSchemaare reported as:- CHANGED - if the property is just updated.
- ADDED - if a new property is added.
- REMOVED - if an existing property is removed.
- NONE - if there is no change for the specific property.
Console Output
Schema Diff: {
"children" : [ {
"name" : "__class__",
"type" : "NONE"
}, {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "account",
"type" : "REMOVED"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "superEntityName",
"type" : "NONE"
}, {
"name" : "allowExtraFieldsInValidation",
"type" : "NONE"
}, {
"name" : "allowExtraFieldsInMapping",
"type" : "NONE"
}, {
"name" : "addMissingOptionalFields",
"type" : "NONE"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "type",
"type" : "NONE"
}, {
"name" : "displayName",
"type" : "NONE"
}, {
"name" : "required",
"type" : "NONE"
}, {
"name" : "array",
"type" : "NONE"
}, {
"name" : "minimumElements",
"type" : "NONE"
}, {
"name" : "maximumElements",
"type" : "NONE"
}, {
"name" : "strictArrays",
"type" : "NONE"
}, {
"name" : "position",
"type" : "NONE"
}, {
"name" : "limitToAllowedValues",
"type" : "NONE"
}, {
"name" : "example",
"type" : "NONE"
}, {
"name" : "primaryKeyPosition",
"type" : "NONE"
}, {
"name" : "primaryKeyType",
"type" : "NONE"
}, {
"name" : "defaultValueExpression",
"type" : "NONE"
}, {
"name" : "indexInEntityDef",
"type" : "NONE"
}, {
"name" : "minimumLength",
"type" : "NONE"
}, {
"name" : "maximumLength",
"type" : "NONE"
}, {
"name" : "allowBlank",
"type" : "NONE"
}, {
"name" : "pattern",
"type" : "NONE"
} ],
"name" : "name",
"type" : "NONE"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "type",
"type" : "NONE"
}, {
"name" : "displayName",
"type" : "NONE"
}, {
"name" : "required",
"type" : "CHANGED"
}, {
"name" : "array",
"type" : "NONE"
}, {
"name" : "minimumElements",
"type" : "NONE"
}, {
"name" : "maximumElements",
"type" : "NONE"
}, {
"name" : "strictArrays",
"type" : "NONE"
}, {
"name" : "position",
"type" : "NONE"
}, {
"name" : "limitToAllowedValues",
"type" : "NONE"
}, {
"name" : "example",
"type" : "NONE"
}, {
"name" : "primaryKeyPosition",
"type" : "NONE"
}, {
"name" : "primaryKeyType",
"type" : "NONE"
}, {
"name" : "defaultValueExpression",
"type" : "NONE"
}, {
"name" : "indexInEntityDef",
"type" : "NONE"
}, {
"name" : "precision",
"type" : "NONE"
}, {
"name" : "scale",
"type" : "NONE"
}, {
"name" : "minimum",
"type" : "NONE"
}, {
"name" : "maximum",
"type" : "NONE"
}, {
"name" : "pattern",
"type" : "NONE"
} ],
"name" : "age",
"type" : "CHANGED"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "type",
"type" : "NONE"
}, {
"name" : "displayName",
"type" : "NONE"
}, {
"name" : "required",
"type" : "NONE"
}, {
"name" : "array",
"type" : "NONE"
}, {
"name" : "minimumElements",
"type" : "NONE"
}, {
"name" : "maximumElements",
"type" : "NONE"
}, {
"name" : "strictArrays",
"type" : "NONE"
}, {
"name" : "position",
"type" : "NONE"
}, {
"name" : "limitToAllowedValues",
"type" : "NONE"
}, {
"name" : "example",
"type" : "NONE"
}, {
"name" : "primaryKeyPosition",
"type" : "NONE"
}, {
"name" : "primaryKeyType",
"type" : "NONE"
}, {
"name" : "defaultValueExpression",
"type" : "NONE"
}, {
"name" : "indexInEntityDef",
"type" : "NONE"
}, {
"name" : "precision",
"type" : "NONE"
}, {
"name" : "scale",
"type" : "NONE"
}, {
"name" : "minimum",
"type" : "NONE"
}, {
"name" : "maximum",
"type" : "NONE"
}, {
"name" : "pattern",
"type" : "NONE"
} ],
"name" : "balance",
"type" : "NONE"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "type",
"type" : "NONE"
}, {
"name" : "displayName",
"type" : "NONE"
}, {
"name" : "required",
"type" : "NONE"
}, {
"name" : "array",
"type" : "NONE"
}, {
"name" : "minimumElements",
"type" : "NONE"
}, {
"name" : "maximumElements",
"type" : "NONE"
}, {
"name" : "strictArrays",
"type" : "NONE"
}, {
"name" : "position",
"type" : "NONE"
}, {
"name" : "limitToAllowedValues",
"type" : "NONE"
}, {
"name" : "example",
"type" : "NONE"
}, {
"name" : "primaryKeyPosition",
"type" : "NONE"
}, {
"name" : "primaryKeyType",
"type" : "NONE"
}, {
"name" : "defaultValueExpression",
"type" : "NONE"
}, {
"name" : "indexInEntityDef",
"type" : "NONE"
} ],
"name" : "active",
"type" : "NONE"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "type",
"type" : "NONE"
}, {
"name" : "displayName",
"type" : "NONE"
}, {
"name" : "required",
"type" : "NONE"
}, {
"name" : "array",
"type" : "NONE"
}, {
"name" : "minimumElements",
"type" : "NONE"
}, {
"name" : "maximumElements",
"type" : "NONE"
}, {
"name" : "strictArrays",
"type" : "NONE"
}, {
"name" : "position",
"type" : "NONE"
}, {
"name" : "limitToAllowedValues",
"type" : "NONE"
}, {
"name" : "example",
"type" : "NONE"
}, {
"name" : "primaryKeyPosition",
"type" : "NONE"
}, {
"name" : "primaryKeyType",
"type" : "NONE"
}, {
"name" : "defaultValueExpression",
"type" : "NONE"
}, {
"name" : "indexInEntityDef",
"type" : "NONE"
}, {
"name" : "precision",
"type" : "NONE"
}, {
"name" : "scale",
"type" : "NONE"
}, {
"name" : "minimum",
"type" : "NONE"
}, {
"name" : "maximum",
"type" : "NONE"
}, {
"name" : "pattern",
"type" : "NONE"
} ],
"name" : "bonuses",
"type" : "NONE"
}, {
"name" : "balanceAge",
"type" : "REMOVED"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "type",
"type" : "NONE"
}, {
"name" : "displayName",
"type" : "NONE"
}, {
"name" : "required",
"type" : "NONE"
}, {
"name" : "array",
"type" : "NONE"
}, {
"name" : "minimumElements",
"type" : "NONE"
}, {
"name" : "maximumElements",
"type" : "NONE"
}, {
"name" : "strictArrays",
"type" : "NONE"
}, {
"name" : "position",
"type" : "NONE"
}, {
"name" : "limitToAllowedValues",
"type" : "NONE"
}, {
"name" : "example",
"type" : "NONE"
}, {
"name" : "primaryKeyPosition",
"type" : "NONE"
}, {
"name" : "primaryKeyType",
"type" : "NONE"
}, {
"name" : "defaultValueExpression",
"type" : "NONE"
}, {
"name" : "indexInEntityDef",
"type" : "CHANGED"
}, {
"name" : "pattern",
"type" : "NONE"
}, {
"name" : "lenientPattern",
"type" : "NONE"
}, {
"name" : "minimum",
"type" : "NONE"
}, {
"name" : "minimumClass",
"type" : "NONE"
}, {
"name" : "maximum",
"type" : "NONE"
}, {
"name" : "maximumClass",
"type" : "NONE"
} ],
"name" : "lastUpdated",
"type" : "CHANGED"
}, {
"children" : [ {
"name" : "name",
"type" : "NONE"
}, {
"name" : "description",
"type" : "NONE"
}, {
"name" : "type",
"type" : "NONE"
}, {
"name" : "displayName",
"type" : "NONE"
}, {
"name" : "required",
"type" : "NONE"
}, {
"name" : "array",
"type" : "NONE"
}, {
"name" : "minimumElements",
"type" : "NONE"
}, {
"name" : "maximumElements",
"type" : "NONE"
}, {
"name" : "strictArrays",
"type" : "NONE"
}, {
"name" : "position",
"type" : "NONE"
}, {
"name" : "limitToAllowedValues",
"type" : "NONE"
}, {
"name" : "example",
"type" : "NONE"
}, {
"name" : "primaryKeyPosition",
"type" : "NONE"
}, {
"name" : "primaryKeyType",
"type" : "NONE"
}, {
"name" : "defaultValueExpression",
"type" : "NONE"
}, {
"name" : "indexInEntityDef",
"type" : "CHANGED"
}, {
"name" : "referencedEntityName",
"type" : "NONE"
} ],
"name" : "accounts",
"type" : "CHANGED"
}, {
"name" : "created_on",
"type" : "ADDED"
} ],
"name" : "customer",
"type" : "CHANGED"
}, {
"name" : "bank",
"type" : "ADDED"
} ],
"name" : "schema-01",
"type" : "CHANGED"
}
