METAMODEL-4: Added capability to parse column and table paths with
authorKasper Sørensen <i.am.kasper.sorensen@gmail.com>
Fri, 23 Aug 2013 08:45:51 +0000 (10:45 +0200)
committerKasper Sørensen <i.am.kasper.sorensen@gmail.com>
Fri, 23 Aug 2013 08:45:51 +0000 (10:45 +0200)
quoted elements in the path.

core/src/main/java/org/apache/metamodel/AbstractDataContext.java
core/src/main/java/org/apache/metamodel/schema/MutableColumn.java
core/src/main/java/org/apache/metamodel/schema/MutableTable.java
core/src/test/java/org/apache/metamodel/AbstractDataContextTest.java

index 77ab3c1..c3d53c4 100644 (file)
  */
 package org.apache.metamodel;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -230,6 +232,21 @@ public abstract class AbstractDataContext implements DataContext {
         if (columnName == null) {
             return null;
         }
+
+        final String[] tokens = tokenizePath(columnName, 3);
+        if (tokens != null) {
+            final Schema schema = getSchemaByToken(tokens[0]);
+            if (schema != null) {
+                final Table table = schema.getTableByName(tokens[1]);
+                if (table != null) {
+                    final Column column = table.getColumnByName(tokens[2]);
+                    if (column != null) {
+                        return column;
+                    }
+                }
+            }
+        }
+
         Schema schema = null;
         final String[] schemaNames = getSchemaNames();
         for (final String schemaName : schemaNames) {
@@ -366,6 +383,18 @@ public abstract class AbstractDataContext implements DataContext {
         if (tableName == null) {
             return null;
         }
+
+        final String[] tokens = tokenizePath(tableName, 2);
+        if (tokens != null) {
+            Schema schema = getSchemaByToken(tokens[0]);
+            if (schema != null) {
+                Table table = schema.getTableByName(tokens[1]);
+                if (table != null) {
+                    return table;
+                }
+            }
+        }
+
         Schema schema = null;
         String[] schemaNames = getSchemaNames();
         for (String schemaName : schemaNames) {
@@ -413,6 +442,75 @@ public abstract class AbstractDataContext implements DataContext {
         return schema.getTableByName(tablePart);
     }
 
+    /**
+     * Tokenizes a path for a table or a column.
+     * 
+     * @param tableName
+     * @param expectedParts
+     * @return
+     */
+    private String[] tokenizePath(String path, int expectedParts) {
+        final List<String> tokens = new ArrayList<String>(expectedParts);
+
+        boolean inQuotes = false;
+        final StringBuilder currentToken = new StringBuilder();
+        for (int i = 0; i < path.length(); i++) {
+            char c = path.charAt(i);
+            if (c == '.' && !inQuotes) {
+                // token finished
+                tokens.add(currentToken.toString());
+                currentToken.setLength(0);
+
+                if (tokens.size() > expectedParts) {
+                    // unsuccesfull - return null
+                    return null;
+                }
+            } else if (c == '"') {
+                if (inQuotes) {
+                    if (i + 1 < path.length() && path.charAt(i + 1) != '.') {
+                        // unsuccesfull - return null
+                        return null;
+                    }
+                } else {
+                    if (currentToken.length() > 0) {
+                        // unsuccesfull - return null
+                        return null;
+                    }
+                }
+                inQuotes = !inQuotes;
+            } else {
+                currentToken.append(c);
+            }
+        }
+
+        if (currentToken.length() > 0) {
+            tokens.add(currentToken.toString());
+        }
+
+        if (tokens.size() == expectedParts - 1) {
+            // add a special-meaning "null" which will be interpreted as the
+            // default schema (since the schema wasn't specified).
+            tokens.add(0, null);
+        } else if (tokens.size() != expectedParts) {
+            return null;
+        }
+
+        return tokens.toArray(new String[tokens.size()]);
+    }
+
+    private Schema getSchemaByToken(String token) {
+        if (token == null) {
+            return getDefaultSchema();
+        }
+        try {
+            return getSchemaByName(token);
+        } catch (RuntimeException e) {
+            // swallow this exception - the attempt did not work and the null
+            // will be treated.
+            return null;
+        }
+    }
+
     private boolean isStartingToken(String partName, String fullName) {
         if (fullName.startsWith(partName)) {
             final int length = partName.length();
index 6308d50..050de15 100644 (file)
@@ -73,6 +73,11 @@ public class MutableColumn extends AbstractColumn implements Serializable {
         setQuote(quote);
     }
 
+    public MutableColumn(String name, Table table) {
+        this(name);
+        setTable(table);
+    }
+
     @Override
     public int getColumnNumber() {
         return _columnNumber;
index 39ad0b2..904fc81 100644 (file)
@@ -68,6 +68,11 @@ public class MutableTable extends AbstractTable implements Serializable {
         setColumns(columns);
     }
 
+    public MutableTable(String name, Schema schema) {
+        this(name);
+        setSchema(schema);
+    }
+
     @Override
     public String getName() {
         return _name;
index 8493a08..ea8a9de 100644 (file)
@@ -19,6 +19,8 @@
 package org.apache.metamodel;
 
 import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 import junit.framework.TestCase;
 import org.apache.metamodel.data.DataSet;
@@ -32,101 +34,130 @@ import org.apache.metamodel.schema.Table;
 
 public class AbstractDataContextTest extends TestCase {
 
-       private class MyDataContext extends AbstractDataContext {
-               @Override
-               public DataSet executeQuery(Query query) throws MetaModelException {
-                       throw new UnsupportedOperationException();
-               }
-
-               @Override
-               protected String[] getSchemaNamesInternal() {
-                       return new String[] { "barfoo", "foobar", "foo.bar" };
-               }
-
-               @Override
-               protected String getDefaultSchemaName() {
-                       return "foobar";
-               }
-
-               @Override
-               protected Schema getSchemaByNameInternal(String name) {
-                       if ("barfoo".equals(name) || "foobar".equals(name)
-                                       || "foo.bar".equals(name)) {
-                               return createSchema(name);
-                       }
-                       throw new IllegalStateException("No such schema: " + name);
-               }
-
-               private Schema createSchema(String name) {
-                       MutableSchema schema = new MutableSchema(name);
-                       MutableTable t1 = new MutableTable("table");
-                       MutableColumn col1 = new MutableColumn("col1");
-                       MutableColumn col2 = new MutableColumn("col2");
-                       t1.addColumn(col1).addColumn(col2);
-                       col1.setTable(t1);
-                       col2.setTable(t1);
-                       MutableTable t2 = new MutableTable("tab.le");
-                       MutableColumn col3 = new MutableColumn("col3");
-                       MutableColumn col4 = new MutableColumn("col4");
-                       t2.addColumn(col3).addColumn(col4);
-                       col3.setTable(t2);
-                       col4.setTable(t2);
-                       schema.addTable(t1).addTable(t2);
-                       t1.setSchema(schema);
-                       t2.setSchema(schema);
-                       return schema;
-               }
-
-       }
-       
-
-       public void testGetColumnByQualifiedLabel() throws Exception {
-               MyDataContext dc = new MyDataContext();
-               Column result;
-
-               result = dc.getColumnByQualifiedLabel("foobar.tab.le.col1");
-               result = dc.getColumnByQualifiedLabel("blabla.tab.le.col4");
-               result = dc.getColumnByQualifiedLabel("FOOBAR.TABLE.COL3");
-               assertNull(result);
-
-               result = dc.getColumnByQualifiedLabel("foobar.table.col1");
-               assertEquals("col1", result.getName());
-               assertEquals("table", result.getTable().getName());
-               assertEquals("foobar", result.getTable().getSchema().getName());
-
-               result = dc.getColumnByQualifiedLabel("foo.bar.table.col1");
-               assertEquals("col1", result.getName());
-               assertEquals("table", result.getTable().getName());
-               assertEquals("foo.bar", result.getTable().getSchema().getName());
-
-               result = dc.getColumnByQualifiedLabel("foobar.tab.le.col3");
-               assertEquals("col3", result.getName());
-               assertEquals("tab.le", result.getTable().getName());
-               assertEquals("foobar", result.getTable().getSchema().getName());
-
-               result = dc.getColumnByQualifiedLabel("FOO.BAR.tab.le.col3");
-               assertEquals("col3", result.getName());
-               assertEquals("tab.le", result.getTable().getName());
-               assertEquals("foo.bar", result.getTable().getSchema().getName());
-
-               result = dc.getColumnByQualifiedLabel("tab.le.col3");
-               assertEquals("col3", result.getName());
-               assertEquals("tab.le", result.getTable().getName());
-               assertEquals("foobar", result.getTable().getSchema().getName());
-       }
-       
-       public void testGetTableByQualfiedLabelSchemaNameInTableName() throws Exception {
+    private class MyDataContext extends AbstractDataContext {
+
+        private final Map<String, Schema> _schemas;
+        private final String _defaultSchemaName;
+
+        public MyDataContext() {
+            this("foobar", createSchema("barfoo"), createSchema("foobar"), createSchema("foo.bar"));
+        }
+
+        public MyDataContext(String defaultSchemaName, Schema... schemas) {
+            _defaultSchemaName = defaultSchemaName;
+            _schemas = new LinkedHashMap<String, Schema>();
+            for (Schema schema : schemas) {
+                _schemas.put(schema.getName(), schema);
+            }
+        }
+
+        @Override
+        public DataSet executeQuery(Query query) throws MetaModelException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected String[] getSchemaNamesInternal() {
+            return _schemas.keySet().toArray(new String[0]);
+        }
+
+        @Override
+        protected String getDefaultSchemaName() {
+            return _defaultSchemaName;
+        }
+
+        @Override
+        protected Schema getSchemaByNameInternal(String name) {
+            Schema schema = _schemas.get(name);
+            if (schema == null) {
+                throw new IllegalStateException("No such schema: " + name);
+            }
+            return schema;
+        }
+    }
+
+    public void testGetTableWithQuotesInLabel() throws Exception {
+        MutableSchema schema1 = new MutableSchema("foo");
+        schema1.addTable(new MutableTable("bar.baz", schema1));
+        MutableSchema schema2 = new MutableSchema("foo.bar");
+        schema2.addTable(new MutableTable("baz", schema2));
+
+        MyDataContext dc = new MyDataContext("foo", schema1, schema2);
+        assertEquals("baz", dc.getTableByQualifiedLabel("foo.bar.baz").getName());
+
+        assertEquals("baz", dc.getTableByQualifiedLabel("\"foo.bar\".baz").getName());
+        assertEquals("baz", dc.getTableByQualifiedLabel("\"foo.bar\".\"baz\"").getName());
+        assertEquals("bar.baz", dc.getTableByQualifiedLabel("foo.\"bar.baz\"").getName());
+        assertEquals("bar.baz", dc.getTableByQualifiedLabel("\"foo\".\"bar.baz\"").getName());
+    }
+
+    public void testGetColumnWithQuotesInLabel() throws Exception {
+        MutableSchema schema = new MutableSchema("foo");
+
+        MutableTable table1 = new MutableTable("bar.baz", schema);
+        schema.addTable(table1);
+        table1.addColumn(new MutableColumn("buuh", table1));
+
+        MutableTable table2 = new MutableTable("bar", schema);
+        schema.addTable(table2);
+        table2.addColumn(new MutableColumn("baz.buuh", table2));
+
+        MyDataContext dc = new MyDataContext("foo", schema);
+        assertEquals("buuh", dc.getColumnByQualifiedLabel("foo.bar.baz.buuh").getName());
+
+        assertEquals("buuh", dc.getColumnByQualifiedLabel("foo.\"bar.baz\".buuh").getName());
+        assertEquals("buuh", dc.getColumnByQualifiedLabel("foo.\"bar.baz\".\"buuh\"").getName());
+        assertEquals("baz.buuh", dc.getColumnByQualifiedLabel("foo.bar.\"baz.buuh\"").getName());
+        assertEquals("baz.buuh", dc.getColumnByQualifiedLabel("\"foo\".bar.\"baz.buuh\"").getName());
+    }
+
+    public void testGetColumnByQualifiedLabel() throws Exception {
+        MyDataContext dc = new MyDataContext();
+        Column result;
+
+        result = dc.getColumnByQualifiedLabel("foobar.tab.le.col1");
+        result = dc.getColumnByQualifiedLabel("blabla.tab.le.col4");
+        result = dc.getColumnByQualifiedLabel("FOOBAR.TABLE.COL3");
+        assertNull(result);
+
+        result = dc.getColumnByQualifiedLabel("foobar.table.col1");
+        assertEquals("col1", result.getName());
+        assertEquals("table", result.getTable().getName());
+        assertEquals("foobar", result.getTable().getSchema().getName());
+
+        result = dc.getColumnByQualifiedLabel("foo.bar.table.col1");
+        assertEquals("col1", result.getName());
+        assertEquals("table", result.getTable().getName());
+        assertEquals("foo.bar", result.getTable().getSchema().getName());
+
+        result = dc.getColumnByQualifiedLabel("foobar.tab.le.col3");
+        assertEquals("col3", result.getName());
+        assertEquals("tab.le", result.getTable().getName());
+        assertEquals("foobar", result.getTable().getSchema().getName());
+
+        result = dc.getColumnByQualifiedLabel("FOO.BAR.tab.le.col3");
+        assertEquals("col3", result.getName());
+        assertEquals("tab.le", result.getTable().getName());
+        assertEquals("foo.bar", result.getTable().getSchema().getName());
+
+        result = dc.getColumnByQualifiedLabel("tab.le.col3");
+        assertEquals("col3", result.getName());
+        assertEquals("tab.le", result.getTable().getName());
+        assertEquals("foobar", result.getTable().getSchema().getName());
+    }
+
+    public void testGetTableByQualfiedLabelSchemaNameInTableName() throws Exception {
         AbstractDataContext dc = new AbstractDataContext() {
             @Override
             public DataSet executeQuery(Query query) throws MetaModelException {
                 return null;
             }
-            
+
             @Override
             protected String[] getSchemaNamesInternal() {
-                return new String[] {"test"};
+                return new String[] { "test" };
             }
-            
+
             @Override
             protected Schema getSchemaByNameInternal(String name) {
                 MutableSchema sch = new MutableSchema("test");
@@ -135,113 +166,120 @@ public class AbstractDataContextTest extends TestCase {
                 sch.addTable(new MutableTable("test_table3").setSchema(sch));
                 return sch;
             }
-            
+
             @Override
             protected String getDefaultSchemaName() {
                 return "test";
             }
         };
-        
+
         assertEquals("test_table1", dc.getTableByQualifiedLabel("test_table1").getName());
         assertEquals("test_table2", dc.getTableByQualifiedLabel("test_table2").getName());
         assertEquals("test_table3", dc.getTableByQualifiedLabel("test_table3").getName());
     }
 
-       public void testGetTableByQualifiedLabel() throws Exception {
-               MyDataContext dc = new MyDataContext();
-
-               Table result;
-
-               result = dc.getTableByQualifiedLabel("FOOBAR.table");
-               assertEquals("table", result.getName());
-               assertEquals("foobar", result.getSchema().getName());
-
-               result = dc.getTableByQualifiedLabel("table");
-               assertEquals("table", result.getName());
-               assertEquals("foobar", result.getSchema().getName());
-
-               result = dc.getTableByQualifiedLabel("foo.bar.table");
-               assertEquals("table", result.getName());
-               assertEquals("foo.bar", result.getSchema().getName());
-
-               result = dc.getTableByQualifiedLabel("foobar.tab.le");
-               assertEquals("tab.le", result.getName());
-               assertEquals("foobar", result.getSchema().getName());
-
-               result = dc.getTableByQualifiedLabel("foo.bar.tab.le");
-               assertEquals("tab.le", result.getName());
-               assertEquals("foo.bar", result.getSchema().getName());
-
-               result = dc.getTableByQualifiedLabel("foo.table");
-               assertNull(result);
-       }
-
-       public void testGetSchemas() throws Exception {
-               MyDataContext dc = new MyDataContext();
-               Schema[] schemas = dc.getSchemas();
-               assertEquals(
-                               "[Schema[name=barfoo], Schema[name=foo.bar], Schema[name=foobar]]",
-                               Arrays.toString(schemas));
-
-               dc.refreshSchemas();
-               schemas = dc.getSchemas();
-               assertEquals(
-                               "[Schema[name=barfoo], Schema[name=foo.bar], Schema[name=foobar]]",
-                               Arrays.toString(schemas));
-       }
-
-       public void testGetColumnByQualifiedLabelWithNameOverlaps()
-                       throws Exception {
-               AbstractDataContext dc = new AbstractDataContext() {
-
-                       @Override
-                       public DataSet executeQuery(Query query) throws MetaModelException {
-                               throw new UnsupportedOperationException();
-                       }
-
-                       @Override
-                       protected String[] getSchemaNamesInternal() {
-                               return new String[] { "sch" };
-                       }
-
-                       @Override
-                       protected Schema getSchemaByNameInternal(String name) {
-                               MutableSchema schema = new MutableSchema("sch");
-                               MutableTable table1 = new MutableTable("tab");
-                               MutableTable table2 = new MutableTable("tab_le");
-                               MutableTable table3 = new MutableTable("table");
-                               MutableTable table4 = new MutableTable("tabl_e");
-                               schema.addTable(table1.addColumn(new MutableColumn("col")
-                                               .setTable(table1)));
-                               schema.addTable(table2.addColumn(new MutableColumn("col")
-                                               .setTable(table2)));
-                               schema.addTable(table3.addColumn(new MutableColumn("col")
-                                               .setTable(table3)));
-                               schema.addTable(table4.addColumn(new MutableColumn("col")
-                                               .setTable(table4)));
-                               return schema;
-                       }
-
-                       @Override
-                       protected String getDefaultSchemaName() {
-                               return "sch";
-                       }
-               };
-
-               assertEquals("tab.col", dc.getColumnByQualifiedLabel("sch.tab.col")
-                               .getQualifiedLabel());
-               assertEquals("table.col", dc.getColumnByQualifiedLabel("sch.table.col")
-                               .getQualifiedLabel());
-               assertEquals("tab_le.col", dc.getColumnByQualifiedLabel(
-                               "sch.tab_le.col").getQualifiedLabel());
-               assertEquals("tabl_e.col", dc.getColumnByQualifiedLabel(
-                               "sch.tabl_e.col").getQualifiedLabel());
-       }
-
-       public void testGetColumnByQualifiedLabelCaseInsensitive() throws Exception {
-               MyDataContext dc = new MyDataContext();
-               Column result = dc.getColumnByQualifiedLabel("FOOBAR.TABLE.COL1");
-               assertNotNull(result);
-               assertEquals("col1", result.getName());
-       }
+    public void testGetTableByQualifiedLabel() throws Exception {
+        MyDataContext dc = new MyDataContext();
+
+        Table result;
+
+        result = dc.getTableByQualifiedLabel("FOOBAR.table");
+        assertEquals("table", result.getName());
+        assertEquals("foobar", result.getSchema().getName());
+
+        result = dc.getTableByQualifiedLabel("table");
+        assertEquals("table", result.getName());
+        assertEquals("foobar", result.getSchema().getName());
+
+        result = dc.getTableByQualifiedLabel("foo.bar.table");
+        assertEquals("table", result.getName());
+        assertEquals("foo.bar", result.getSchema().getName());
+
+        result = dc.getTableByQualifiedLabel("foobar.tab.le");
+        assertEquals("tab.le", result.getName());
+        assertEquals("foobar", result.getSchema().getName());
+
+        result = dc.getTableByQualifiedLabel("foo.bar.tab.le");
+        assertEquals("tab.le", result.getName());
+        assertEquals("foo.bar", result.getSchema().getName());
+
+        result = dc.getTableByQualifiedLabel("foo.table");
+        assertNull(result);
+    }
+
+    public void testGetSchemas() throws Exception {
+        MyDataContext dc = new MyDataContext();
+        Schema[] schemas = dc.getSchemas();
+        assertEquals("[Schema[name=barfoo], Schema[name=foo.bar], Schema[name=foobar]]", Arrays.toString(schemas));
+
+        dc.refreshSchemas();
+        schemas = dc.getSchemas();
+        assertEquals("[Schema[name=barfoo], Schema[name=foo.bar], Schema[name=foobar]]", Arrays.toString(schemas));
+    }
+
+    public void testGetColumnByQualifiedLabelWithNameOverlaps() throws Exception {
+        AbstractDataContext dc = new AbstractDataContext() {
+
+            @Override
+            public DataSet executeQuery(Query query) throws MetaModelException {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            protected String[] getSchemaNamesInternal() {
+                return new String[] { "sch" };
+            }
+
+            @Override
+            protected Schema getSchemaByNameInternal(String name) {
+                MutableSchema schema = new MutableSchema("sch");
+                MutableTable table1 = new MutableTable("tab");
+                MutableTable table2 = new MutableTable("tab_le");
+                MutableTable table3 = new MutableTable("table");
+                MutableTable table4 = new MutableTable("tabl_e");
+                schema.addTable(table1.addColumn(new MutableColumn("col").setTable(table1)));
+                schema.addTable(table2.addColumn(new MutableColumn("col").setTable(table2)));
+                schema.addTable(table3.addColumn(new MutableColumn("col").setTable(table3)));
+                schema.addTable(table4.addColumn(new MutableColumn("col").setTable(table4)));
+                return schema;
+            }
+
+            @Override
+            protected String getDefaultSchemaName() {
+                return "sch";
+            }
+        };
+
+        assertEquals("tab.col", dc.getColumnByQualifiedLabel("sch.tab.col").getQualifiedLabel());
+        assertEquals("table.col", dc.getColumnByQualifiedLabel("sch.table.col").getQualifiedLabel());
+        assertEquals("tab_le.col", dc.getColumnByQualifiedLabel("sch.tab_le.col").getQualifiedLabel());
+        assertEquals("tabl_e.col", dc.getColumnByQualifiedLabel("sch.tabl_e.col").getQualifiedLabel());
+    }
+
+    public void testGetColumnByQualifiedLabelCaseInsensitive() throws Exception {
+        MyDataContext dc = new MyDataContext();
+        Column result = dc.getColumnByQualifiedLabel("FOOBAR.TABLE.COL1");
+        assertNotNull(result);
+        assertEquals("col1", result.getName());
+    }
+
+    private Schema createSchema(String name) {
+        MutableSchema schema = new MutableSchema(name);
+        MutableTable t1 = new MutableTable("table");
+        MutableColumn col1 = new MutableColumn("col1");
+        MutableColumn col2 = new MutableColumn("col2");
+        t1.addColumn(col1).addColumn(col2);
+        col1.setTable(t1);
+        col2.setTable(t1);
+        MutableTable t2 = new MutableTable("tab.le");
+        MutableColumn col3 = new MutableColumn("col3");
+        MutableColumn col4 = new MutableColumn("col4");
+        t2.addColumn(col3).addColumn(col4);
+        col3.setTable(t2);
+        col4.setTable(t2);
+        schema.addTable(t1).addTable(t2);
+        t1.setSchema(schema);
+        t2.setSchema(schema);
+        return schema;
+    }
 }
\ No newline at end of file