All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tbrugz.sqldiff.RenameDetector Maven / Gradle / Ivy

package tbrugz.sqldiff;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import tbrugz.sqldiff.model.ChangeType;
import tbrugz.sqldiff.model.ColumnDiff;
import tbrugz.sqldiff.model.DBIdentifiableDiff;
import tbrugz.sqldiff.model.Diff;
import tbrugz.sqldiff.model.TableDiff;
import tbrugz.sqldiff.util.SimilarityCalculator;
import tbrugz.sqldump.dbmodel.Constraint;
import tbrugz.sqldump.dbmodel.DBIdentifiable;
import tbrugz.sqldump.dbmodel.DBObjectType;
import tbrugz.sqldump.dbmodel.Index;
import tbrugz.sqldump.dbmodel.Table;

class RenameTuple {
	Diff add;
	Diff drop;
	double similarity;
	
	public RenameTuple(Diff add, Diff drop, double similarity) {
		this.add = add;
		this.drop = drop;
		this.similarity = similarity;
	}
	
	@Override
	public String toString() {
		return "RenameTuple[ add="+add+" ; drop="+drop+" ]";
	}
}

public class RenameDetector {
	
	static final Log log = LogFactory.getLog(RenameDetector.class);
	
	public static final DBObjectType[] RENAME_TYPES = {
		DBObjectType.TABLE, DBObjectType.COLUMN, DBObjectType.INDEX, DBObjectType.CONSTRAINT
	};
	
	static List detectTableRenames(Collection tableDiffs, double minSimilarity) {
		List ltadd = getDiffsOfType(tableDiffs, ChangeType.ADD);
		List ltdrop = getDiffsOfType(tableDiffs, ChangeType.DROP);
		
		log.debug("ltadd-size: '"+ltadd.size()+"' ; ltdrop-size: '"+ltdrop.size()+"'");
		if(ltadd.size()==0 || ltdrop.size()==0) {
			return new ArrayList();
		}
		
		//if multiple renames, return ok if all that sim > minSim
		List renames = new ArrayList();
		for(TableDiff tadd: ltadd) {
			for(TableDiff tdrop: ltdrop) {
				double similarity = SimilarityCalculator.instance().similarity(tadd.getTable(), tdrop.getTable());
				log.debug("t-add: '"+tadd.getNamedObject()+"' ; t-drop: '"+tdrop.getNamedObject()+"' ; sim: "+similarity);
				if(similarity>=minSimilarity) {
					renames.add(new RenameTuple(tadd, tdrop, similarity));
				}
			}
		}
		
		return renames;
	}
	
	static List detectColumnRenames(Collection columnDiffs, double minSimilarity) {
		List lcadd = getDiffsOfType(columnDiffs, ChangeType.ADD);
		List lcdrop = getDiffsOfType(columnDiffs, ChangeType.DROP);
		
		log.debug("lcadd-size: '"+lcadd.size()+"' ; lcdrop-size: '"+lcdrop.size()+"'");
		if(lcadd.size()==0 || lcdrop.size()==0) {
			return new ArrayList();
		}
		
		Set colsAdded = new HashSet();
		Set colsDropped = new HashSet();
		List renames = new ArrayList();
		
		for(int i=0;i=minSimilarity) {
					log.debug("renamed; c-add: '"+cadd+"' ; c-drop: '"+cdrop+"' ; sim: "+similarity);
					String cAddId = cadd.getNamedObject().getSchemaName()+"."+cadd.getNamedObject().getName()+"."+cadd.getColumn().getName();
					String cDropId = cdrop.getNamedObject().getSchemaName()+"."+cdrop.getNamedObject().getName()+"."+cdrop.getPreviousColumn().getName();
					if(!colsDropped.add(cDropId)) {
						log.warn("column '"+cDropId+"' \"renamed-from\" multiple times");
					}
					if(!colsAdded.add(cAddId)) {
						log.warn("column '"+cAddId+"' \"renamed-to\" multiple times");
					}
					renames.add(new RenameTuple(cadd, cdrop, similarity));
				}
			}
		}
		
		return renames;
	}

	static List detectDbIdRenames(Collection dbidDiffs, DBObjectType dbotype, double minSimilarity) {
		List lIdAdd = getDiffsOfType(dbidDiffs, ChangeType.ADD);
		List lIdDrop = getDiffsOfType(dbidDiffs, ChangeType.DROP);
		
		log.debug("lIdAdd-size: '"+lIdAdd.size()+"' ; lIdDrop-size: '"+lIdDrop.size()+"'");
		if(lIdAdd.size()==0 || lIdDrop.size()==0) {
			return new ArrayList();
		}
		
		List renames = new ArrayList();
		
		for(int i=0;i*/ diffs, List renames) {
		for(RenameTuple rt: renames) {
			boolean added = false;
			int removedCount = 0;
			if(rt.add instanceof TableDiff) {
				TableDiff tdrename = new TableDiff(ChangeType.RENAME, (Table) rt.add.getNamedObject(), rt.drop.getNamedObject().getSchemaName(), rt.drop.getNamedObject().getName(), null);
				added = diffs.add(tdrename);
				//TODO add & drop columns!
			}
			else if(rt.add instanceof ColumnDiff) {
				ColumnDiff cdrename = new ColumnDiff(ChangeType.RENAME, rt.add.getNamedObject(), ((ColumnDiff)rt.drop).getPreviousColumn(), ((ColumnDiff)rt.add).getColumn());
				added = diffs.add(cdrename);
			}
			else if(rt.add instanceof DBIdentifiableDiff) {
				DBIdentifiableDiff dff = (DBIdentifiableDiff) rt.add;
				DBIdentifiableDiff idrename = new DBIdentifiableDiff(ChangeType.RENAME, (DBIdentifiable) rt.drop.getNamedObject(), (DBIdentifiable) rt.add.getNamedObject(), dff.getOwnerTableName());
				added = diffs.add(idrename);
			}
			if(!added) { throw new RuntimeException("could not add rename: "+rt); }
			removedCount += diffs.remove(rt.add)?1:0;
			removedCount += diffs.remove(rt.drop)?1:0;
			if(removedCount!=2) { throw new RuntimeException("could not remove add/drop diffs: "+rt); }
		}
	}

	static void validateConflictingRenames(List renames) {
		Set stadd = new HashSet();
		Set stdrop = new HashSet();
		for(RenameTuple rt: renames) {
			//throw UndecidableRenameException ?
			if(! stadd.add(rt.add)) {
				throw new ConflictingChangesException("a table can't be renamed more than once [add table = '"+rt.add+"'; similarity = "+rt.similarity+"]");
			}
			if(! stdrop.add(rt.drop)) {
				throw new ConflictingChangesException("a table can't be renamed more than once [drop table = '"+rt.drop+"'; similarity = "+rt.similarity+"]");
			}
		}
	}
	
	public static int detectAndDoTableRenames(Collection tableDiffs, double minSimilarity) {
		//get renames
		List renames = detectTableRenames(tableDiffs, minSimilarity);
		
		//validate & do renames
		return validateAndDoRenames(tableDiffs, renames, "table");
	}

	public static int detectAndDoColumnRenames(Collection columnDiffs, double minSimilarity) {
		//get renames
		List renames = detectColumnRenames(columnDiffs, minSimilarity);

		//validate & do renames
		return validateAndDoRenames(columnDiffs, renames, "column");
	}

	public static int detectAndDoIndexRenames(Collection dbIdDiffs, double minSimilarity) {
		//get renames
		List renames = detectDbIdRenames(dbIdDiffs, DBObjectType.INDEX, minSimilarity);

		//validate & do renames
		return validateAndDoRenames(dbIdDiffs, renames, "index");
	}

	public static int detectAndDoConstraintRenames(Collection dbIdDiffs, double minSimilarity) {
		//get renames
		List renames = detectDbIdRenames(dbIdDiffs, DBObjectType.CONSTRAINT, minSimilarity);

		//validate & do renames
		return validateAndDoRenames(dbIdDiffs, renames, "constraint");
	}
	
	static int validateAndDoRenames(Collection diffs, List renames, String diffType) {
		if(renames.size()==0) {
			log.info("no "+diffType+" renames detected");
		}
		else {
			log.info(renames.size()+" "+diffType+" renames detected");

			//validate renames
			validateConflictingRenames(renames);
			
			//do renames
			doRenames(diffs, renames);
		}

		return renames.size();
	}
	
	static  List getDiffsOfType(Collection difflist, ChangeType type) {
		List ret = new ArrayList();
		for(T d: difflist) {
			if(d.getChangeType().equals(type)) {
				ret.add(d);
			}
		}
		return ret;
	}
	
	static boolean equalsApartFromName(DBIdentifiable o1, DBIdentifiable o2) {
		if(o1 instanceof Index && o2 instanceof Index) {
			Index i1 = (Index) o1;
			Index i2 = (Index) o2;
			if(i1.getColumns().equals(i2.getColumns())
				&& i1.getLocal()==i2.getLocal()
				&& i1.getReverse()==i2.getReverse()
				&& i1.getIndexType()==i2.getIndexType()
				&& i1.getTableName().equals(i2.getTableName())
				&& ( (i1.getType()==null && i2.getType()==null) || i1.getType().equals(i2.getType()) )
				&& i1.isUnique() == i2.isUnique()
				) {
				return true;
			}
		}
		else if(o1 instanceof Constraint && o2 instanceof Constraint) {
			Constraint c1 = (Constraint) o1;
			Constraint c2 = (Constraint) o2;
			if(c1.getType()==c2.getType()
				&& c1.getUniqueColumns().equals(c2.getUniqueColumns())
				&& ( (c1.getCheckDescription()==null && c2.getCheckDescription()==null) || c1.getCheckDescription().equals(c2.getCheckDescription()) )
				) {
				return true;
			}
		}
		else if(DBIdentifiable.getType(o1)==DBIdentifiable.getType(o2)) {
			log.warn("equalsApartFromName: unknown type: "+DBIdentifiable.getType(o1));
		}
		else {
			log.debug("equalsApartFromName: incompatible types: "+DBIdentifiable.getType(o1)+", "+DBIdentifiable.getType(o2));
		}
		
		return false;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy