Author: cbegin Date: Sat Jan 21 19:13:39 2006 New Revision: 371173 URL: http://svn.apache.org/viewcvs?rev=371173&view=rev Log: Implemented stats based name matcher for use with auto crud ops generation
Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Canonicalizer.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Match.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/MatchCalculator.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/NameMatcher.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Column.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Database.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/DatabaseFactory.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Table.java ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/CanonicalizerTest.java ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/DatabaseMetadataTest.java ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/MatchCalculatorTest.java ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/NameMatcherTest.java Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Canonicalizer.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Canonicalizer.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Canonicalizer.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Canonicalizer.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,177 @@ +package com.ibatis.sqlmap.engine.mapper; + +import java.util.StringTokenizer; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; + +public class Canonicalizer { + + public Map buildCanonicalMap(String[] originals) { + return buildCanonicalMap(originals, null); + } + public Map buildCanonicalMap(String[] originals, String parentName) { + Map map = new HashMap(); + for (int i=0; i < originals.length; i++) { + map.put(originals[i], originals[i]); + } + upperCase(map); + removeUnderscores(map); + removePKFK(map); + removePrefixes(map); + removeSuffixes(map); + removePluralization(map); + removeParentName(map, parentName); + return map; + } + + private void removeParentName(Map map, String parentName) { + if (parentName != null) { + parentName = parentName.toUpperCase(); + Iterator i = map.keySet().iterator(); + while (i.hasNext()) { + String original = (String) i.next(); + String canonical = (String) map.get(original); + if (canonical.startsWith(parentName)) { + map.put(original, canonical.substring(parentName.length())); + } + if (canonical.endsWith(parentName)) { + map.put(original, canonical.substring(0, canonical.length() - parentName.length())); + } + } + } + } + + private void upperCase(Map map) { + Iterator i = map.keySet().iterator(); + while (i.hasNext()) { + String original = (String) i.next(); + String canonical = (String) map.get(original); + map.put(original, canonical.toUpperCase()); + } + } + + private void removePKFK(Map map) { + Iterator i = map.keySet().iterator(); + while (i.hasNext()) { + String original = (String) i.next(); + String canonical = (String) map.get(original); + if (canonical.startsWith("PK")) { + map.put(original, canonical.substring(2)); + } else if (canonical.startsWith("FK")) { + map.put(original, canonical.substring(2)); + } + if (canonical.endsWith("PK")) { + map.put(original, canonical.substring(0, canonical.length() - 2)); + } else if (canonical.endsWith("FK")) { + map.put(original, canonical.substring(0, canonical.length() - 2)); + } + } + } + + private void removePrefixes(Map map) { + int prefix = findPrefixLength(map); + + if (prefix > 1) { + Iterator i = map.keySet().iterator(); + while (i.hasNext()) { + String original = (String) i.next(); + String canonical = (String) map.get(original); + map.put(original, canonical.substring(prefix)); + } + } + } + + private void removeSuffixes(Map map) { + int suffix = findSuffixLength(map); + + if (suffix > 1) { + Iterator i = map.keySet().iterator(); + while (i.hasNext()) { + String original = (String) i.next(); + String canonical = (String) map.get(original); + map.put(original, canonical.substring(0, canonical.length() - suffix)); + } + } + } + + private int findPrefixLength(Map map) { + String[] originals = (String[])map.keySet().toArray(new String[map.keySet().size()]); + char[] samples = ((String) map.get(findShortestString(originals))).toCharArray(); + int prefix = 0; + for (int i=0; i < samples.length; i++) { + for (int j=0; j < originals.length; j++) { + String original = originals[j]; + String canonical = (String) map.get(original); + if (canonical.charAt(prefix) != samples[i]) { + return prefix; + } + } + prefix++; + } + if (prefix == samples.length) { + prefix = 0; + } + return prefix; + } + + private int findSuffixLength(Map map) { + String[] originals = (String[])map.keySet().toArray(new String[map.keySet().size()]); + char[] samples = ((String) map.get(findShortestString(originals))).toCharArray(); + int suffix = 0; + for (int i=0; i < samples.length; i++) { + for (int j=0; j < originals.length; j++) { + String original = originals[j]; + String canonical = (String) map.get(original); + if (canonical.charAt(canonical.length() - suffix - 1) != samples[samples.length - i - 1]) { + return suffix; + } + } + suffix++; + } + if (suffix == samples.length) { + suffix = 0; + } + return suffix; + } + + private String findShortestString(String[] originals) { + String shortest = originals[0]; + for (int i=0; i < originals.length; i++) { + if (originals[i].length() < shortest.length()) { + shortest = originals[i]; + } + } + return shortest; + } + + private void removeUnderscores (Map map) { + Iterator i = map.keySet().iterator(); + while (i.hasNext()) { + String original = (String) i.next(); + String canonical = (String) map.get(original); + map.put(original, removeUnderscoresFromString(canonical)); + } + } + + private void removePluralization (Map map) { + Iterator i = map.keySet().iterator(); + while (i.hasNext()) { + String original = (String) i.next(); + String canonical = (String) map.get(original); + if (canonical.endsWith("S") || canonical.endsWith("s")) { + map.put(original, canonical.substring(0, canonical.length() - 1)); + } + } + } + + private String removeUnderscoresFromString (String original) { + StringBuffer canonical = new StringBuffer(); + StringTokenizer parser = new StringTokenizer (original, "_", false); + while(parser.hasMoreTokens()) { + canonical.append(parser.nextToken()); + } + return canonical.toString(); + } + +} Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Match.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Match.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Match.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/Match.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,32 @@ +package com.ibatis.sqlmap.engine.mapper; + +public class Match { + + private String property; + private String field; + private double matchScore; + + public Match(String property, String field, double matchScore) { + this.property = property; + this.field = field; + this.matchScore = matchScore; + } + + public String getProperty() { + return property; + } + + public String getField() { + return field; + } + + public double getMatchScore() { + return matchScore; + } + + + public String toString() { + return property + " => " + field + " ("+matchScore+")"; + } + +} Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/MatchCalculator.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/MatchCalculator.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/MatchCalculator.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/MatchCalculator.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,69 @@ +package com.ibatis.sqlmap.engine.mapper; + +import java.util.Set; +import java.util.HashSet; +import java.util.Iterator; + +public class MatchCalculator { + + private static final int SET_BEGIN = 2; + private static final int SET_END = 5; + private static final double MAX_VALUE = 1; + + public MatchCalculator() { + } + + public double calculateMatch (String first, String second) { + + Set firstSet = buildSets(first); + Set secondSet = buildSets(second); + + double value1 = compareSets(firstSet, secondSet); + double value2 = compareSets(secondSet, firstSet); + return (value1 + value2) / 2; + } + + private Set buildSets(String string) { + Set set = new HashSet(); + char[] chars = string.toUpperCase().toCharArray(); + for (int i = SET_BEGIN; i <= SET_END; i++) { + setsOf(i, chars, set); + } + return set; + } + + private void setsOf(int size, char[] chars, Set set) { + for (int i=0; i < chars.length - size + 1; i++) { + char[] group = new char[size]; + for (int j=0; j < group.length; j++) { + group[j] = chars[i+j]; + } + set.add(new String(group)); + } + } + + private double compareSets(Set firstSet, Set secondSet) { + double value = MAX_VALUE; + double interval = calculateInterval(firstSet, secondSet); + Iterator i = firstSet.iterator(); + while (i.hasNext()) { + String group = (String)i.next(); + if (!secondSet.contains(group)) { + value -= interval; + } + } + return value; + } + + private double calculateInterval(Set firstSet, Set secondSet) { + double interval; + if (firstSet.size() > secondSet.size()) { + interval = MAX_VALUE / firstSet.size(); + } else { + interval = MAX_VALUE / secondSet.size(); + } + return interval; + } + + +} Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/NameMatcher.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/NameMatcher.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/NameMatcher.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/NameMatcher.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,90 @@ +package com.ibatis.sqlmap.engine.mapper; + +import java.util.*; + +public class NameMatcher { + + public Map matchNames(String[] properties, String[] fields) { + Map propertyMap = invertMap(buildCanonicalMap(properties)); + Map fieldMap = invertMap(buildCanonicalMap(fields)); + + String[] canonicalProperties = setToStringArray(propertyMap.keySet()); + String[] canonicalFields = setToStringArray(fieldMap.keySet()); + + // consider building in both directions + // consider tracking which fields have already been mapped to avoid duplicate mappings + List matchList = buildMatchList(canonicalProperties, canonicalFields); + + Map matchedNames = new HashMap(); + Iterator matches = matchList.iterator(); + while(matches.hasNext()) { + Match match = (Match)matches.next(); + String property = (String) propertyMap.get(match.getProperty()); + String field = (String) fieldMap.get(match.getField()); + matchedNames.put(property, field); + } + return matchedNames; + } + + private Map buildCanonicalMap(String[] properties) { + return new Canonicalizer().buildCanonicalMap(properties); + } + + private String[] setToStringArray(Set set) { + return (String[]) set.toArray(new String[set.size()]); + } + + private List buildMatchList(String[] canonicalProperties, String[] canonicalFields) { + List matchList = new LinkedList(); + MatchCalculator calc = new MatchCalculator(); + for (int i = 0; i < canonicalProperties.length; i++) { + for (int j = 0; j < canonicalFields.length; j++) { + String prop = canonicalProperties[i]; + String field = canonicalFields[j]; + double score = calc.calculateMatch(prop, field); + Match match = new Match(prop, field, score); + matchList.add(match); + } + } + sortMatches(matchList); + removeDuplicatesAndLowScores (matchList); + return matchList; + } + + private void removeDuplicatesAndLowScores(List matchList) { + Set usedProperties = new HashSet(); + Set usedFields = new HashSet(); + Iterator i = matchList.iterator(); + while (i.hasNext()) { + Match m = (Match)i.next(); + if (usedProperties.contains(m.getProperty()) || usedFields.contains(m.getField()) || m.getMatchScore() < 0.40) { + i.remove(); + } else { + usedProperties.add(m.getProperty()); + usedFields.add(m.getField()); + } + } + + } + + private void sortMatches(List matchList) { + Collections.sort(matchList, new Comparator () { + public int compare(Object o1, Object o2) { + Match m1 = (Match) o1; + Match m2 = (Match) o2; + return m1.getMatchScore() < m2.getMatchScore() ? 1 : m1.getMatchScore() > m2.getMatchScore() ? -1 : 0; + } + }); + } + + private Map invertMap(Map original) { + Map inverse = new HashMap(); + Iterator keys = original.keySet().iterator(); + while (keys.hasNext()) { + Object key = keys.next(); + Object value = original.get(key); + inverse.put(value, key); + } + return inverse; + } +} Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Column.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Column.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Column.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Column.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,40 @@ +package com.ibatis.sqlmap.engine.mapper.metadata; + +public class Column { + + private String name; + private int type; + + public Column(String name, int type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public int getType() { + return type; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Column column = (Column) o; + + if (type != column.type) return false; + if (name != null ? !name.equals(column.name) : column.name != null) return false; + + return true; + } + + public int hashCode() { + int result; + result = (name != null ? name.hashCode() : 0); + result = 29 * result + type; + return result; + } + +} Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Database.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Database.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Database.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Database.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,57 @@ +package com.ibatis.sqlmap.engine.mapper.metadata; + +import java.util.HashMap; +import java.util.Map; + +public class Database { + + private String catalog; + private String schema; + + private Map tables = new HashMap(); + + public Database(String catalog, String schema) { + this.catalog = catalog; + this.schema = schema; + } + + public String getCatalog() { + return catalog; + } + + public String getSchema() { + return schema; + } + + public void addTable(Table table) { + tables.put(table.getName(), table); + } + + public Table getTable(String name) { + return (Table)tables.get(name); + } + + public String[] getTableNames() { + return (String[])tables.keySet().toArray(new String[tables.size()]); + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Database database = (Database) o; + + if (catalog != null ? !catalog.equals(database.catalog) : database.catalog != null) return false; + if (schema != null ? !schema.equals(database.schema) : database.schema != null) return false; + + return true; + } + + public int hashCode() { + int result; + result = (catalog != null ? catalog.hashCode() : 0); + result = 29 * result + (schema != null ? schema.hashCode() : 0); + return result; + } + +} Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/DatabaseFactory.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/DatabaseFactory.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/DatabaseFactory.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/DatabaseFactory.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,42 @@ +package com.ibatis.sqlmap.engine.mapper.metadata; + +import javax.sql.DataSource; +import java.sql.SQLException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.DatabaseMetaData; + +public class DatabaseFactory { + + private DatabaseFactory() { + } + + public static Database newDatabase (DataSource dataSource, String catalog, String schema) throws SQLException { + Database database = new Database (catalog, schema); + Connection conn = dataSource.getConnection(); + ResultSet rs = null; + try { + DatabaseMetaData dbmd = conn.getMetaData(); + rs = dbmd.getColumns(catalog, schema, null, null); + while (rs.next()) { + String tableName = rs.getString ("TABLE_NAME"); + String columnName = rs.getString ("COLUMN_NAME"); + int dataType = Integer.parseInt(rs.getString ("DATA_TYPE")); + Table table = database.getTable(tableName); + if (table == null) { + table = new Table(tableName); + database.addTable(table); + } + table.addColumn(new Column(columnName, dataType)); + } + } finally { + try { + if (rs != null) rs.close(); + } finally { + conn.close(); + } + } + return database; + } + +} Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Table.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Table.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Table.java (added) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapper/metadata/Table.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,47 @@ +package com.ibatis.sqlmap.engine.mapper.metadata; + +import java.util.HashMap; +import java.util.Map; + +public class Table { + + private String name; + + private Map columns = new HashMap(); + + public Table(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void addColumn (Column col) { + columns.put(col.getName(), col); + } + + public Column getColumn (String name) { + return (Column) columns.get(name); + } + + public String[] getColumnNames () { + return (String[])columns.keySet().toArray(new String[columns.size()]); + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Table table = (Table) o; + + if (name != null ? !name.equals(table.name) : table.name != null) return false; + + return true; + } + + public int hashCode() { + return (name != null ? name.hashCode() : 0); + } + +} Added: ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/CanonicalizerTest.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/CanonicalizerTest.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/CanonicalizerTest.java (added) +++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/CanonicalizerTest.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,104 @@ +package com.ibatis.sqlmap.mapper; + +import junit.framework.TestCase; +import com.ibatis.sqlmap.engine.mapper.Canonicalizer; + +import java.util.Map; + +public class CanonicalizerTest extends TestCase { + + public void testShouldRemoveUnderscoresFromName () { + Canonicalizer matcher = new Canonicalizer(); + String original = "ACC_FIRST_NAME"; + String expected = "ACCFIRSTNAME"; + Map map = matcher.buildCanonicalMap (new String[]{original}); + String canonical = (String) map.get(original); + assertEquals(expected, canonical); + } + + public void testShouldUppercase () { + Canonicalizer matcher = new Canonicalizer(); + String original = "AccFirstName"; + String expected = "ACCFIRSTNAME"; + Map map = matcher.buildCanonicalMap (new String[]{original}); + String canonical = (String) map.get(original); + assertEquals(expected, canonical); + } + + public void testShouldRemovePluralization () { + Canonicalizer matcher = new Canonicalizer(); + String original = "ACCFIRSTNAMES"; + String expected = "ACCFIRSTNAME"; + Map map = matcher.buildCanonicalMap (new String[]{original}); + String canonical = (String) map.get(original); + assertEquals(expected, canonical); + } + + public void testShouldRemovePrefix () { + Canonicalizer matcher = new Canonicalizer(); + String[] originals = new String[]{"ACC_FIRSTNAME", "ACC_LASTNAME", "ACC_BIRTHDATE", "ACC_LEVEL"}; + String[] expected = new String[]{"FIRSTNAME", "LASTNAME", "BIRTHDATE", "LEVEL"}; + Map map = matcher.buildCanonicalMap (originals); + for (int i=0; i < originals.length; i++) { + String canonical = (String) map.get(originals[i]); + assertEquals(expected[i], canonical); + } + } + + public void testShouldRemoveSuffix () { + Canonicalizer matcher = new Canonicalizer(); + String[] originals = new String[]{"FIRSTNAME_ACC", "LASTNAME_ACC", "BIRTHDATE_ACC", "LEVEL_ACC"}; + String[] expected = new String[]{"FIRSTNAME", "LASTNAME", "BIRTHDATE", "LEVEL"}; + Map map = matcher.buildCanonicalMap (originals); + for (int i=0; i < originals.length; i++) { + String canonical = (String) map.get(originals[i]); + assertEquals(expected[i], canonical); + } + } + + public void testShouldRemovePKFK () { + Canonicalizer matcher = new Canonicalizer(); + String[] originals = new String[]{"PK_FIRSTNAME", "LASTNAME_PK", "BIRTHDATE_FK", "FK_LEVEL"}; + String[] expected = new String[]{"FIRSTNAME", "LASTNAME", "BIRTHDATE", "LEVEL"}; + Map map = matcher.buildCanonicalMap (originals); + for (int i=0; i < originals.length; i++) { + String canonical = (String) map.get(originals[i]); + assertEquals(expected[i], canonical); + } + } + + public void testShouldRemoveParentName () { + Canonicalizer matcher = new Canonicalizer(); + String parentName = "Person"; + String[] originals = new String[]{"Person_ID, FIRSTNAME", "LASTNAME", "BIRTHDATE", "LEVEL_Person"}; + String[] expected = new String[]{"ID, FIRSTNAME", "LASTNAME", "BIRTHDATE", "LEVEL"}; + Map map = matcher.buildCanonicalMap (originals, parentName); + for (int i=0; i < originals.length; i++) { + String canonical = (String) map.get(originals[i]); + assertEquals(expected[i], canonical); + } + } + + public void testShouldNotRemovePrefixWhenOnlyColumn () { + Canonicalizer matcher = new Canonicalizer(); + String[] originals = new String[]{"ACCFIRSTNAME"}; + String[] expected = new String[]{"ACCFIRSTNAME"}; + Map map = matcher.buildCanonicalMap (originals); + for (int i=0; i < originals.length; i++) { + String canonical = (String) map.get(originals[i]); + assertEquals(expected[i], canonical); + } + } + + public void testShouldNotRemovePrefixWhenSomePrefixesDoNotMatch () { + Canonicalizer matcher = new Canonicalizer(); + String[] originals = new String[]{"ACCFIRSTNAME", "ACCLASTNAME", "ACCBIRTHDATE", "XACCLEVEL"}; + String[] expected = new String[]{"ACCFIRSTNAME", "ACCLASTNAME", "ACCBIRTHDATE", "XACCLEVEL"}; + Map map = matcher.buildCanonicalMap (originals); + for (int i=0; i < originals.length; i++) { + String canonical = (String) map.get(originals[i]); + assertEquals(expected[i], canonical); + } + } + +} Added: ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/DatabaseMetadataTest.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/DatabaseMetadataTest.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/DatabaseMetadataTest.java (added) +++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/DatabaseMetadataTest.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,37 @@ +package com.ibatis.sqlmap.mapper; + +import com.ibatis.sqlmap.engine.mapper.metadata.Database; +import com.ibatis.sqlmap.engine.mapper.metadata.DatabaseFactory; +import com.ibatis.sqlmap.engine.mapper.metadata.Table; +import com.ibatis.sqlmap.BaseSqlMapTest; + +public class DatabaseMetadataTest extends BaseSqlMapTest { + + protected void setUp() throws Exception { + initSqlMap("com/ibatis/sqlmap/maps/SqlMapConfig.xml", null); + initScript("scripts/account-init.sql"); + } + + public void testDatabaseMetaData() throws Exception { + Database db = DatabaseFactory.newDatabase(sqlMap.getDataSource(), null, null); + + Table table = db.getTable("ACCOUNT"); + + assertNotNull(table); + assertEquals("ACCOUNT", table.getName()); + + String[] columnNames = table.getColumnNames(); + + assertEquals(8, columnNames.length); + + assertNotNull(table.getColumn("ACC_BANNER_OPTION")); + assertNotNull(table.getColumn("ACC_EMAIL")); + assertNotNull(table.getColumn("ACC_FIRST_NAME")); + assertNotNull(table.getColumn("ACC_LAST_NAME")); + assertNotNull(table.getColumn("ACC_ID")); + assertNotNull(table.getColumn("ACC_DATE_ADDED")); + assertNotNull(table.getColumn("ACC_AGE")); + assertNotNull(table.getColumn("ACC_CART_OPTION")); + } + +} Added: ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/MatchCalculatorTest.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/MatchCalculatorTest.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/MatchCalculatorTest.java (added) +++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/MatchCalculatorTest.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,36 @@ +package com.ibatis.sqlmap.mapper; + +import junit.framework.TestCase; +import com.ibatis.sqlmap.engine.mapper.MatchCalculator; + +public class MatchCalculatorTest extends TestCase { + + public void testWillNotFindMatchesCorrectlyWithoutMoreContext() { + assertTrue(isMatch("firstName", "LASTNAME")); + assertFalse(isMatch("lastName", "ACC_LAST_NAME")); + assertFalse(isMatch("lastName", "ACC_LAST_NAME_FK")); + } + + public void testShouldFindMatchesWithinAGivenThreshold() { + assertTrue(isMatch("firstName", "FIRSTNAME")); + assertTrue(isMatch("firstName", "ACC_FIRSTNAME")); + assertTrue(isMatch("firstName", "ACC_FIRST_NAME")); + assertTrue(isMatch("firstName", "ACC_FIRST_NAME_FK")); + assertTrue(isMatch("id", "id")); + + assertTrue(isMatch("lastName", "LASTNAME")); + assertTrue(isMatch("lastName", "ACC_LASTNAME")); + + assertFalse(isMatch("firstName", "ACC_LASTNAME")); + assertFalse(isMatch("firstName", "ACC_LAST_NAME")); + assertFalse(isMatch("firstName", "ACC_LAST_NAME_FK")); + assertFalse(isMatch("id", "PersonId")); + } + + private boolean isMatch(String first, String second) { + double matchBar = 0.55; + return new MatchCalculator().calculateMatch(first, second) >= matchBar; + } + + +} Added: ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/NameMatcherTest.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/NameMatcherTest.java?rev=371173&view=auto ============================================================================== --- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/NameMatcherTest.java (added) +++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/mapper/NameMatcherTest.java Sat Jan 21 19:13:39 2006 @@ -0,0 +1,52 @@ +package com.ibatis.sqlmap.mapper; + +import com.ibatis.sqlmap.engine.mapper.NameMatcher; +import junit.framework.TestCase; + +import java.util.Map; + +public class NameMatcherTest extends TestCase { + + public void testShouldCorrectlyMatchMostOfTheseFairlyComplexNamePairs() { + String[] properties = new String[]{"id", "username", "orderDate", "shipAddress1", "shipAddress2", "shipCity", "shipState", "shipZip", "shipCountry", "billAddress1", "billAddress2", "billCity", "billState", "billZip", "billCountry", "courier", "totalPrice", "billToFirstName", "billToLastName", "shipToFirstName", "shipToLastName", "creditCard", "expiryDate", "cardType", "locale", "status"}; + String[] fields = new String[]{"orderid", "userid", "orderdate", "shipaddr1", "shipaddr2", "shipcity", "shipstate", "shipzip", "shipcountry", "billaddr1", "billaddr2", "billcity", "billstate", "billzip", "billcountry", "courier", "totalprice", "billtofirstname", "billtolastname", "shiptofirstname", "shiptolastname", "creditcard", "exprdate", "cardtype", "locale"}; + Map map = new NameMatcher().matchNames(fields, properties); + + // unmatched + assertNull(map.get("orderid")); + + // match collision, userid matches id better than orderid + assertEquals("id", map.get("userid")); + + // good matches + assertEquals("cardType", map.get("cardtype")); + assertEquals("creditCard", map.get("creditcard")); + assertEquals("expiryDate", map.get("exprdate")); + + assertEquals("totalPrice", map.get("totalprice")); + assertEquals("courier", map.get("courier")); + assertEquals("orderDate", map.get("orderdate")); + assertEquals("locale", map.get("locale")); + + assertEquals("billToFirstName", map.get("billtofirstname")); + assertEquals("billToLastName", map.get("billtolastname")); + assertEquals("billAddress1", map.get("billaddr1")); + assertEquals("billAddress2", map.get("billaddr2")); + assertEquals("billCity", map.get("billcity")); + assertEquals("billState", map.get("billstate")); + assertEquals("billCountry", map.get("billcountry")); + assertEquals("billZip", map.get("billzip")); + + assertEquals("shipToFirstName", map.get("shiptofirstname")); + assertEquals("shipToLastName", map.get("shiptolastname")); + assertEquals("shipAddress1", map.get("shipaddr1")); + assertEquals("shipAddress2", map.get("shipaddr2")); + assertEquals("shipCountry", map.get("shipcountry")); + assertEquals("shipZip", map.get("shipzip")); + assertEquals("shipCity", map.get("shipcity")); + assertEquals("shipState", map.get("shipstate")); + } + +} + +