You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ka...@apache.org on 2013/07/19 11:33:10 UTC

[27/61] [partial] Hard rename of all 'org/eobjects' folders to 'org/apache'.

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/test/java/org/apache/metamodel/AbstractDataContextTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/AbstractDataContextTest.java b/core/src/test/java/org/apache/metamodel/AbstractDataContextTest.java
new file mode 100644
index 0000000..4320a5b
--- /dev/null
+++ b/core/src/test/java/org/apache/metamodel/AbstractDataContextTest.java
@@ -0,0 +1,247 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eobjects.metamodel;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.MutableColumn;
+import org.eobjects.metamodel.schema.MutableSchema;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.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 {
+        AbstractDataContext dc = new AbstractDataContext() {
+            @Override
+            public DataSet executeQuery(Query query) throws MetaModelException {
+                return null;
+            }
+            
+            @Override
+            protected String[] getSchemaNamesInternal() {
+                return new String[] {"test"};
+            }
+            
+            @Override
+            protected Schema getSchemaByNameInternal(String name) {
+                MutableSchema sch = new MutableSchema("test");
+                sch.addTable(new MutableTable("test_table1").setSchema(sch));
+                sch.addTable(new MutableTable("test_table2").setSchema(sch));
+                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());
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/test/java/org/apache/metamodel/CompositeDataContextTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/CompositeDataContextTest.java b/core/src/test/java/org/apache/metamodel/CompositeDataContextTest.java
new file mode 100644
index 0000000..0a2e0f7
--- /dev/null
+++ b/core/src/test/java/org/apache/metamodel/CompositeDataContextTest.java
@@ -0,0 +1,117 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eobjects.metamodel;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.schema.CompositeSchema;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+
+public class CompositeDataContextTest extends TestCase {
+
+	/**
+	 * A "typical scenario": Use a database and a CSV file to create a query
+	 * that joins tables from each
+	 */
+	public void testBaseCaseCompositeQuery() throws Exception {
+		DataContext dc1 = new MockDataContext("schema1", "table1", "");
+		DataContext dc2 = new MockDataContext("schema2", "table2", "");
+
+		DataContext composite = new CompositeDataContext(dc1, dc2);
+
+		assertEquals("[schema1, schema2]",
+				Arrays.toString(composite.getSchemaNames()));
+		assertSame(dc1.getDefaultSchema(), composite.getDefaultSchema());
+
+		DataSet ds = composite.query()
+				.from(dc1.getDefaultSchema().getTables()[0]).select("foo")
+				.execute();
+		List<Object[]> objectArrays = ds.toObjectArrays();
+		assertEquals("1", objectArrays.get(0)[0]);
+		assertEquals("2", objectArrays.get(1)[0]);
+		assertEquals(4, objectArrays.size());
+	}
+
+	public void testSchemaNameClashes() throws Exception {
+		DataContext dc1 = new MockDataContext("schema", "table1", "");
+		DataContext dc2 = new MockDataContext("schema", "table2", "");
+
+		DataContext composite = new CompositeDataContext(dc1, dc2);
+
+		assertEquals("[schema]",
+				Arrays.toString(composite.getSchemaNames()));
+
+		Schema schema = composite.getDefaultSchema();
+		assertEquals(4, schema.getTableCount());
+		assertEquals("[table1, an_empty_table, table2, an_empty_table]",
+				Arrays.toString(schema.getTableNames()));
+		assertTrue(schema instanceof CompositeSchema);
+	}
+
+	public void testJoinSameTableNames() throws Exception {
+		DataContext dc1 = new MockDataContext("schema", "table", "dc1");
+		DataContext dc2 = new MockDataContext("schema", "table", "dc2");
+
+		DataContext composite = new CompositeDataContext(dc1, dc2);
+
+		assertEquals("[schema]",
+				Arrays.toString(composite.getSchemaNames()));
+
+		Schema schema = composite.getDefaultSchema();
+		assertEquals(4, schema.getTableCount());
+		assertEquals("[table, an_empty_table, table, an_empty_table]", Arrays.toString(schema.getTableNames()));
+		assertTrue(schema instanceof CompositeSchema);
+		Table[] tables = schema.getTables();
+        Table table1 = tables[0];
+        Table table2 = tables[2];
+        assertNotSame(table1, table2);
+
+		Query q = composite
+				.query()
+				.from(table1)
+				.leftJoin(table2)
+				.on(table1.getColumnByName("foo"),
+						table2.getColumnByName("foo"))
+				.select(table1.getColumnByName("foo"),
+						table2.getColumnByName("foo"),
+						table1.getColumnByName("bar"),
+						table2.getColumnByName("baz")).toQuery();
+		assertEquals(
+				"SELECT table.foo, table.foo, table.bar, table.baz "
+						+ "FROM schema.table LEFT JOIN schema.table ON table.foo = table.foo",
+				q.toSql());
+
+		DataSet ds = composite.executeQuery(q);
+		assertTrue(ds.next());
+		assertEquals("Row[values=[1, 1, hello, world]]", ds.getRow().toString());
+		assertTrue(ds.next());
+		assertEquals("Row[values=[2, 2, dc1, world]]", ds.getRow().toString());
+		assertTrue(ds.next());
+		assertEquals("Row[values=[3, 3, hi, dc2]]", ds.getRow().toString());
+		assertTrue(ds.next());
+		assertEquals("Row[values=[4, 4, yo, world]]", ds.getRow().toString());
+		assertFalse(ds.next());
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/test/java/org/apache/metamodel/MetaModelHelperTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/MetaModelHelperTest.java b/core/src/test/java/org/apache/metamodel/MetaModelHelperTest.java
new file mode 100644
index 0000000..50c1ad1
--- /dev/null
+++ b/core/src/test/java/org/apache/metamodel/MetaModelHelperTest.java
@@ -0,0 +1,327 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eobjects.metamodel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.data.DataSetHeader;
+import org.eobjects.metamodel.data.DefaultRow;
+import org.eobjects.metamodel.data.EmptyDataSet;
+import org.eobjects.metamodel.data.InMemoryDataSet;
+import org.eobjects.metamodel.data.Row;
+import org.eobjects.metamodel.data.SimpleDataSetHeader;
+import org.eobjects.metamodel.data.SubSelectionDataSet;
+import org.eobjects.metamodel.query.FilterItem;
+import org.eobjects.metamodel.query.FromItem;
+import org.eobjects.metamodel.query.JoinType;
+import org.eobjects.metamodel.query.OperatorType;
+import org.eobjects.metamodel.query.OrderByItem;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.ColumnType;
+import org.eobjects.metamodel.schema.MutableColumn;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+
+public class MetaModelHelperTest extends MetaModelTestCase {
+
+    public void testLeftJoin() throws Exception {
+        SelectItem si1 = new SelectItem(new MutableColumn("person_id", ColumnType.INTEGER));
+        SelectItem si2 = new SelectItem(new MutableColumn("person_name", ColumnType.VARCHAR));
+        SelectItem si3 = new SelectItem(new MutableColumn("person_age", ColumnType.INTEGER));
+        SelectItem si4 = new SelectItem(new MutableColumn("person_role_id", ColumnType.INTEGER));
+        SelectItem si5 = new SelectItem(new MutableColumn("role_id", ColumnType.INTEGER));
+        SelectItem si6 = new SelectItem(new MutableColumn("role_name", ColumnType.VARCHAR));
+        SelectItem si7 = new SelectItem(new MutableColumn("role_code", ColumnType.VARCHAR));
+        List<Object[]> data1 = new ArrayList<Object[]>();
+        data1.add(new Object[] { 1, "peter", 18, 1 });
+        data1.add(new Object[] { 2, "tom", 19, 2 });
+        data1.add(new Object[] { 3, "betty", 19, null });
+        data1.add(new Object[] { 4, "barbara", 17, 3 });
+        data1.add(new Object[] { 5, "susie", 18, 4 });
+
+        List<Object[]> data2 = new ArrayList<Object[]>();
+        data2.add(new Object[] { 1, "class president", "clpr" });
+        data2.add(new Object[] { 2, "bad boy", "bb" });
+        data2.add(new Object[] { 4, "trying harder", "try" });
+
+        DataSet ds1 = createDataSet(new SelectItem[] { si1, si2, si3, si4 }, data1);
+        DataSet ds2 = createDataSet(new SelectItem[] { si5, si6, si7 }, data2);
+        FilterItem[] onConditions = new FilterItem[1];
+        onConditions[0] = new FilterItem(si4, OperatorType.EQUALS_TO, si5);
+
+        DataSet result = MetaModelHelper.getLeftJoin(ds1, ds2, onConditions);
+        List<Object[]> objectArrays = result.toObjectArrays();
+        assertEquals("[1, peter, 18, 1, 1, class president, clpr]", Arrays.toString(objectArrays.get(0)));
+        assertEquals("[2, tom, 19, 2, 2, bad boy, bb]", Arrays.toString(objectArrays.get(1)));
+        assertEquals("[3, betty, 19, null, null, null, null]", Arrays.toString(objectArrays.get(2)));
+        assertEquals("[4, barbara, 17, 3, null, null, null]", Arrays.toString(objectArrays.get(3)));
+        assertEquals("[5, susie, 18, 4, 4, trying harder, try]", Arrays.toString(objectArrays.get(4)));
+        assertEquals(5, objectArrays.size());
+    }
+
+    public void testRightJoin() throws Exception {
+        SelectItem si1 = new SelectItem(new MutableColumn("person_id", ColumnType.INTEGER));
+        SelectItem si2 = new SelectItem(new MutableColumn("person_name", ColumnType.VARCHAR));
+        SelectItem si3 = new SelectItem(new MutableColumn("person_age", ColumnType.INTEGER));
+        SelectItem si4 = new SelectItem(new MutableColumn("person_role_id", ColumnType.INTEGER));
+        SelectItem si5 = new SelectItem(new MutableColumn("role_id", ColumnType.INTEGER));
+        SelectItem si6 = new SelectItem(new MutableColumn("role_name", ColumnType.VARCHAR));
+        SelectItem si7 = new SelectItem(new MutableColumn("role_code", ColumnType.VARCHAR));
+        List<Object[]> data1 = new ArrayList<Object[]>();
+        data1.add(new Object[] { 1, "peter", 18, 1 });
+        data1.add(new Object[] { 2, "tom", 19, 2 });
+        data1.add(new Object[] { 3, "betty", 19, null });
+        data1.add(new Object[] { 4, "barbara", 17, 3 });
+
+        List<Object[]> data2 = new ArrayList<Object[]>();
+        data2.add(new Object[] { 1, "class president", "clpr" });
+        data2.add(new Object[] { 2, "bad boy", "bb" });
+        data2.add(new Object[] { 4, "trying harder", "try" });
+
+        DataSet ds1 = createDataSet(new SelectItem[] { si1, si2, si3, si4 }, data1);
+        DataSet ds2 = createDataSet(new SelectItem[] { si5, si6, si7 }, data2);
+        FilterItem[] onConditions = new FilterItem[1];
+        onConditions[0] = new FilterItem(si4, OperatorType.EQUALS_TO, si5);
+
+        DataSet result = MetaModelHelper.getRightJoin(ds1, ds2, onConditions);
+        List<Object[]> objectArrays = result.toObjectArrays();
+        assertEquals("[1, peter, 18, 1, 1, class president, clpr]", Arrays.toString(objectArrays.get(0)));
+        assertEquals("[2, tom, 19, 2, 2, bad boy, bb]", Arrays.toString(objectArrays.get(1)));
+        assertEquals("[null, null, null, null, 4, trying harder, try]", Arrays.toString(objectArrays.get(2)));
+        assertEquals(3, objectArrays.size());
+    }
+
+    public void testSimpleCarthesianProduct() throws Exception {
+        DataSet dataSet = MetaModelHelper.getCarthesianProduct(createDataSet1(), createDataSet2());
+
+        assertEquals(2, dataSet.getSelectItems().length);
+        assertTrue(dataSet.next());
+        assertEquals("Row[values=[f, b]]", dataSet.getRow().toString());
+        assertTrue(dataSet.next());
+        assertEquals("Row[values=[f, a]]", dataSet.getRow().toString());
+        assertTrue(dataSet.next());
+        assertTrue(dataSet.next());
+        assertTrue(dataSet.next());
+        assertTrue(dataSet.next());
+        assertTrue(dataSet.next());
+        assertTrue(dataSet.next());
+        assertTrue(dataSet.next());
+        assertEquals("Row[values=[o, r]]", dataSet.getRow().toString());
+        assertFalse(dataSet.next());
+    }
+
+    public void testTripleCarthesianProduct() throws Exception {
+        DataSet dataSet = MetaModelHelper.getCarthesianProduct(createDataSet1(), createDataSet2(), createDataSet3());
+        assertEquals(4, dataSet.getSelectItems().length);
+        for (int i = 0; i < 3 * 3 * 2; i++) {
+            assertTrue("Assertion failed at i=" + i, dataSet.next());
+        }
+        assertFalse(dataSet.next());
+    }
+
+    public void testTripleCarthesianProductWithWhereItems() throws Exception {
+        DataSet ds1 = createDataSet1();
+        DataSet ds2 = createDataSet2();
+        DataSet[] dataSets = new DataSet[] { ds1, ds2, };
+        FilterItem w1 = new FilterItem(ds1.getSelectItems()[0], OperatorType.EQUALS_TO, "f");
+        DataSet dataSet = MetaModelHelper.getCarthesianProduct(dataSets, w1);
+        assertEquals(2, dataSet.getSelectItems().length);
+        for (int i = 0; i < 1 * 3; i++) {
+            assertTrue("Assertion failed at i=" + i, dataSet.next());
+            assertEquals("f", dataSet.getRow().getValue(0));
+        }
+        assertFalse(dataSet.next());
+    }
+
+    public void testGetCarthesianProductNoRows() throws Exception {
+        DataSet dataSet = MetaModelHelper.getCarthesianProduct(createDataSet4(), createDataSet2(), createDataSet3());
+        assertEquals(4, dataSet.getSelectItems().length);
+        assertFalse(dataSet.next());
+
+        dataSet = MetaModelHelper.getCarthesianProduct(createDataSet1(), createDataSet4(), createDataSet3());
+        assertEquals(4, dataSet.getSelectItems().length);
+        assertFalse(dataSet.next());
+
+        dataSet = MetaModelHelper.getCarthesianProduct(createDataSet1(), createDataSet2(), createDataSet4());
+        assertEquals(3, dataSet.getSelectItems().length);
+        assertFalse(dataSet.next());
+    }
+
+    public void testGetOrdered() throws Exception {
+        DataSet dataSet = createDataSet3();
+        List<OrderByItem> orderByItems = new ArrayList<OrderByItem>();
+        orderByItems.add(new OrderByItem(dataSet.getSelectItems()[0]));
+
+        dataSet = MetaModelHelper.getOrdered(dataSet, orderByItems);
+        assertTrue(dataSet.next());
+        assertEquals("Row[values=[w00p, true]]", dataSet.getRow().toString());
+        assertTrue(dataSet.next());
+        assertEquals("Row[values=[yippie, false]]", dataSet.getRow().toString());
+        assertFalse(dataSet.next());
+    }
+
+    private DataSet createDataSet1() {
+        List<Object[]> data1 = new ArrayList<Object[]>();
+        data1.add(new Object[] { "f" });
+        data1.add(new Object[] { "o" });
+        data1.add(new Object[] { "o" });
+        DataSet dataSet1 = createDataSet(
+                new SelectItem[] { new SelectItem(new MutableColumn("foo", ColumnType.VARCHAR)) }, data1);
+        return dataSet1;
+    }
+
+    private DataSet createDataSet2() {
+        List<Object[]> data2 = new ArrayList<Object[]>();
+        data2.add(new Object[] { "b" });
+        data2.add(new Object[] { "a" });
+        data2.add(new Object[] { "r" });
+        DataSet dataSet2 = createDataSet(new SelectItem[] { new SelectItem("bar", "bar") }, data2);
+        return dataSet2;
+    }
+
+    private DataSet createDataSet3() {
+        List<Object[]> data3 = new ArrayList<Object[]>();
+        data3.add(new Object[] { "w00p", true });
+        data3.add(new Object[] { "yippie", false });
+        DataSet dataSet3 = createDataSet(new SelectItem[] { new SelectItem("expression", "e"),
+                new SelectItem("webish?", "w") }, data3);
+        return dataSet3;
+    }
+
+    private DataSet createDataSet4() {
+        List<Object[]> data4 = new ArrayList<Object[]>();
+        DataSet dataSet4 = createDataSet(new SelectItem[] { new SelectItem("abc", "abc") }, data4);
+        return dataSet4;
+    }
+
+    public void testGetTables() throws Exception {
+        MutableTable table1 = new MutableTable("table1");
+        MutableTable table2 = new MutableTable("table2");
+        MutableColumn t1column1 = new MutableColumn("t1c1", ColumnType.BIGINT);
+        MutableColumn t2column1 = new MutableColumn("t2c1", ColumnType.BIGINT);
+        MutableColumn t2column2 = new MutableColumn("t2c2", ColumnType.BIGINT);
+        table1.addColumn(t1column1);
+        t1column1.setTable(table1);
+        table2.addColumn(t2column1);
+        t2column1.setTable(table2);
+        table2.addColumn(t2column2);
+        t2column2.setTable(table2);
+
+        ArrayList<Table> tableList = new ArrayList<Table>();
+        tableList.add(table1);
+
+        ArrayList<Column> columnList = new ArrayList<Column>();
+        columnList.add(t2column1);
+
+        Table[] tables = MetaModelHelper.getTables(tableList, columnList);
+        assertEquals(2, tables.length);
+        assertTrue(Arrays.asList(tables).contains(table1));
+        assertTrue(Arrays.asList(tables).contains(table2));
+    }
+
+    public void testGetTableColumns() throws Exception {
+        MutableTable table1 = new MutableTable("table1");
+        MutableColumn column1 = new MutableColumn("c1", ColumnType.BIGINT);
+        MutableColumn column2 = new MutableColumn("c2", ColumnType.BIGINT);
+        MutableColumn column3 = new MutableColumn("c3", ColumnType.BIGINT);
+        table1.addColumn(column1);
+        column1.setTable(table1);
+        table1.addColumn(column2);
+        column2.setTable(table1);
+        table1.addColumn(column3);
+        column3.setTable(table1);
+
+        ArrayList<Column> columnList = new ArrayList<Column>();
+
+        Column[] columns = MetaModelHelper.getTableColumns(table1, columnList);
+        assertEquals(0, columns.length);
+
+        columnList.add(column1);
+        columnList.add(column3);
+
+        columns = MetaModelHelper.getTableColumns(table1, columnList);
+        assertEquals(2, columns.length);
+        assertSame(column1, columns[0]);
+        assertSame(column3, columns[1]);
+    }
+
+    public void testGetTableFromItems() throws Exception {
+        Schema schema = getExampleSchema();
+        Table contributorTable = schema.getTableByName(TABLE_CONTRIBUTOR);
+        Table projectTable = schema.getTableByName(TABLE_PROJECT);
+        Table projectContributorTable = schema.getTableByName(TABLE_PROJECT_CONTRIBUTOR);
+
+        FromItem sqFromItem = new FromItem(new Query().from(projectTable).from(projectContributorTable));
+        FromItem fromItem = new FromItem(JoinType.INNER, new FromItem(contributorTable), sqFromItem, new SelectItem[0],
+                new SelectItem[0]);
+        Query q = new Query().from(fromItem);
+
+        FromItem[] fromItems = MetaModelHelper.getTableFromItems(q);
+        assertEquals(3, fromItems.length);
+        assertEquals("[MetaModelSchema.contributor, MetaModelSchema.project, MetaModelSchema.project_contributor]",
+                Arrays.toString(fromItems));
+    }
+
+    public void testGetSelectionNoRows() throws Exception {
+        SelectItem item1 = new SelectItem("foo", "f");
+        SelectItem item2 = new SelectItem("bar", "b");
+        SelectItem item3 = new SelectItem("baz", "bz");
+        List<SelectItem> selectItems1 = Arrays.asList(item1, item2, item3);
+        List<SelectItem> selectItems2 = Arrays.asList(item2, item1);
+
+        DataSet ds = MetaModelHelper.getSelection(selectItems2, new EmptyDataSet(selectItems1));
+        assertEquals(SubSelectionDataSet.class, ds.getClass());
+
+        assertEquals("[bar AS b, foo AS f]", Arrays.toString(ds.getSelectItems()));
+    }
+
+    public void testLeftJoinNoRowsOrSingleRow() throws Exception {
+        SelectItem item1 = new SelectItem("foo", "f");
+        SelectItem item2 = new SelectItem("bar", "b");
+        SelectItem item3 = new SelectItem("baz", "z");
+        List<SelectItem> selectItems1 = Arrays.asList(item1, item2);
+        List<SelectItem> selectItems2 = Arrays.asList(item3);
+
+        DataSet ds1 = new EmptyDataSet(selectItems1);
+        DataSet ds2 = new EmptyDataSet(selectItems2);
+
+        DataSet joinedDs = MetaModelHelper.getLeftJoin(ds1, ds2, new FilterItem[] { new FilterItem(item2,
+                OperatorType.EQUALS_TO, item3) });
+
+        assertEquals(SubSelectionDataSet.class, joinedDs.getClass());
+        assertEquals("[foo AS f, bar AS b, baz AS z]", Arrays.toString(joinedDs.getSelectItems()));
+
+        DataSetHeader header1 = new SimpleDataSetHeader(selectItems1);
+        Row row = new DefaultRow(header1, new Object[] { 1, 2 }, null);
+        ds1 = new InMemoryDataSet(header1, row);
+
+        joinedDs = MetaModelHelper.getLeftJoin(ds1, ds2, new FilterItem[] { new FilterItem(item2,
+                OperatorType.EQUALS_TO, item3) });
+        assertEquals("[foo AS f, bar AS b, baz AS z]", Arrays.toString(joinedDs.getSelectItems()));
+        assertTrue(joinedDs.next());
+        assertEquals("Row[values=[1, 2, null]]", joinedDs.getRow().toString());
+        assertFalse(joinedDs.next());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java b/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java
new file mode 100644
index 0000000..6f3e5b1
--- /dev/null
+++ b/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java
@@ -0,0 +1,199 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eobjects.metamodel;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.data.DefaultRow;
+import org.eobjects.metamodel.data.EmptyDataSet;
+import org.eobjects.metamodel.data.InMemoryDataSet;
+import org.eobjects.metamodel.data.Row;
+import org.eobjects.metamodel.data.SimpleDataSetHeader;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.ColumnType;
+import org.eobjects.metamodel.schema.MutableColumn;
+import org.eobjects.metamodel.schema.MutableRelationship;
+import org.eobjects.metamodel.schema.MutableSchema;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.TableType;
+
+/**
+ * Convenient super-class to use for unittesting
+ */
+public abstract class MetaModelTestCase extends TestCase {
+
+    public static final String COLUMN_CONTRIBUTOR_COUNTRY = "country";
+    public static final String COLUMN_CONTRIBUTOR_NAME = "name";
+    public static final String COLUMN_CONTRIBUTOR_CONTRIBUTOR_ID = "contributor_id";
+
+    public static final String COLUMN_PROJECT_PROJECT_ID = "project_id";
+    public static final String COLUMN_PROJECT_NAME = "name";
+    public static final String COLUMN_PROJECT_LINES_OF_CODE = "lines_of_code";
+    public static final String COLUMN_PROJECT_PARENT_PROJECT_ID = "parent_project_id";
+
+    public static final String COLUMN_ROLE_PROJECT_ID = "project_id";
+    public static final String COLUMN_ROLE_CONTRIBUTOR_ID = "contributor_id";
+    public static final String COLUMN_ROLE_ROLE_NAME = "name";
+
+    public static final String COLUMN_PROJECT_CONTRIBUTOR_CONTRIBUTOR = "contributor";
+    public static final String COLUMN_PROJECT_CONTRIBUTOR_ROLE = "role";
+    public static final String COLUMN_PROJECT_CONTRIBUTOR_PROJECT = "project";
+
+    public static final String TABLE_PROJECT_CONTRIBUTOR = "project_contributor";
+    public static final String TABLE_ROLE = "role";
+    public static final String TABLE_PROJECT = "project";
+    public static final String TABLE_CONTRIBUTOR = "contributor";
+
+    /**
+     * Creates an example schema with three tables and a view:
+     * <ul>
+     * <li>contributor[contributor_id,name,country] (TABLE)</li>
+     * <li>project[project_id,name,lines_of_code,parent_project_id] (TABLE)</li>
+     * <li>role[contributor_id,project_id,role_name] (TABLE)</li>
+     * <li>project_contributor[contributor,project,role] (VIEW)</li>
+     * </ul>
+     * The example schema is good for testing purposes and possess various
+     * features of the schema model:
+     * <ul>
+     * <li>Relations between tables: one-Contributor-to-many-Role's and
+     * many-Role's-to-one-Project</li>
+     * <li>Recursive relations: A project can have a parent project</li>
+     * <li>Views: The ProjectContributor view</li>
+     * </ul>
+     */
+    protected Schema getExampleSchema() {
+        MutableSchema schema = new MutableSchema("MetaModelSchema");
+
+        MutableTable table1 = new MutableTable(TABLE_CONTRIBUTOR, TableType.TABLE, schema);
+        Column column1 = new MutableColumn(COLUMN_CONTRIBUTOR_CONTRIBUTOR_ID, ColumnType.INTEGER, table1, 0, false)
+                .setIndexed(true).setPrimaryKey(true);
+        Column column2 = new MutableColumn(COLUMN_CONTRIBUTOR_NAME, ColumnType.VARCHAR, table1, 1, false);
+        Column column3 = new MutableColumn(COLUMN_CONTRIBUTOR_COUNTRY, ColumnType.VARCHAR, table1, 2, true);
+        table1.setColumns(column1, column2, column3);
+
+        MutableTable table2 = new MutableTable(TABLE_PROJECT, TableType.TABLE, schema);
+        Column column4 = new MutableColumn(COLUMN_PROJECT_PROJECT_ID, ColumnType.INTEGER, table2, 0, false)
+                .setPrimaryKey(true);
+        Column column5 = new MutableColumn(COLUMN_PROJECT_NAME, ColumnType.VARCHAR, table2, 1, false);
+        Column column6 = new MutableColumn(COLUMN_PROJECT_LINES_OF_CODE, ColumnType.BIGINT, table2, 2, true);
+        Column column7 = new MutableColumn(COLUMN_PROJECT_PARENT_PROJECT_ID, ColumnType.INTEGER, table2, 3, true);
+        table2.setColumns(column4, column5, column6, column7);
+
+        MutableTable table3 = new MutableTable(TABLE_ROLE, TableType.TABLE, schema);
+        Column column8 = new MutableColumn(COLUMN_ROLE_CONTRIBUTOR_ID, ColumnType.INTEGER, table3, 0, false)
+                .setPrimaryKey(true);
+        Column column9 = new MutableColumn(COLUMN_ROLE_PROJECT_ID, ColumnType.INTEGER, table3, 1, false)
+                .setPrimaryKey(true);
+        Column column10 = new MutableColumn(COLUMN_ROLE_ROLE_NAME, ColumnType.VARCHAR, table3, 2, false);
+        table3.setColumns(column8, column9, column10);
+
+        MutableTable table4 = new MutableTable(TABLE_PROJECT_CONTRIBUTOR, TableType.VIEW, schema);
+        Column column11 = new MutableColumn(COLUMN_PROJECT_CONTRIBUTOR_CONTRIBUTOR, ColumnType.VARCHAR, table4, 0,
+                false);
+        Column column12 = new MutableColumn(COLUMN_PROJECT_CONTRIBUTOR_PROJECT, ColumnType.VARCHAR, table4, 1, false);
+        Column column13 = new MutableColumn(COLUMN_PROJECT_CONTRIBUTOR_ROLE, ColumnType.VARCHAR, table4, 2, false);
+        ArrayList<Column> columnList = new ArrayList<Column>();
+        columnList.add(column11);
+        columnList.add(column12);
+        columnList.add(column13);
+        table4.setColumns(columnList);
+
+        // one-Contributor-to-many-Role's
+        MutableRelationship.createRelationship(new Column[] { column1 }, new Column[] { column8 });
+
+        // one-Project-to-many-Role's
+        MutableRelationship.createRelationship(new Column[] { column4 }, new Column[] { column9 });
+
+        // view relation [contributor -> contributor_name]
+        MutableRelationship.createRelationship(new Column[] { column2 }, new Column[] { column11 });
+
+        // view relation [project -> project_name]
+        MutableRelationship.createRelationship(new Column[] { column5 }, new Column[] { column12 });
+
+        // view relation [role -> role_name]
+        MutableRelationship.createRelationship(new Column[] { column10 }, new Column[] { column13 });
+
+        schema.setTables(table1, table2, table3, table4);
+        return schema;
+    }
+
+    protected static DataSet createDataSet(SelectItem[] selectItems, List<Object[]> data) {
+        if (data.isEmpty()) {
+            return new EmptyDataSet(selectItems);
+        }
+
+        SimpleDataSetHeader header = new SimpleDataSetHeader(selectItems);
+
+        List<Row> rows = new ArrayList<Row>();
+        for (Object[] objects : data) {
+            rows.add(new DefaultRow(header, objects));
+        }
+        return new InMemoryDataSet(header, rows);
+    }
+
+    private List<Object> _mocks = new ArrayList<Object>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        _mocks.clear();
+    }
+
+    public <T extends Object> T createMock(Class<T> clazz) {
+        T mock = EasyMock.createMock(clazz);
+        _mocks.add(mock);
+        return mock;
+    }
+
+    public void verifyMocks() {
+        EasyMock.verify(_mocks.toArray());
+    }
+
+    public void replayMocks() {
+        EasyMock.replay(_mocks.toArray());
+    }
+
+    public void assertEquals(DataSet ds1, DataSet ds2) {
+        assertEquals(Arrays.toString(ds1.getSelectItems()), Arrays.toString(ds2.getSelectItems()));
+        boolean ds1next = true;
+        while (ds1next) {
+            ds1next = ds1.next();
+            boolean ds2next = ds2.next();
+            assertEquals("DataSet 1 next=" + ds1next, ds1next, ds2next);
+            if (ds1next) {
+                Row row1 = ds1.getRow();
+                Row row2 = ds2.getRow();
+                assertEquals(row1, row2);
+            }
+        }
+    }
+
+    protected File getTestResourceAsFile(String filename) {
+        return new File("src/test/resources/" + filename);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/test/java/org/apache/metamodel/MockDataContext.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/MockDataContext.java b/core/src/test/java/org/apache/metamodel/MockDataContext.java
new file mode 100644
index 0000000..5d95034
--- /dev/null
+++ b/core/src/test/java/org/apache/metamodel/MockDataContext.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eobjects.metamodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eobjects.metamodel.data.CachingDataSetHeader;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.data.DataSetHeader;
+import org.eobjects.metamodel.data.DefaultRow;
+import org.eobjects.metamodel.data.EmptyDataSet;
+import org.eobjects.metamodel.data.InMemoryDataSet;
+import org.eobjects.metamodel.data.Row;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.ColumnType;
+import org.eobjects.metamodel.schema.MutableColumn;
+import org.eobjects.metamodel.schema.MutableSchema;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+
+public class MockDataContext extends QueryPostprocessDataContext {
+
+    private final String _schemaName;
+    private final String _tableName;
+    private final String _value;
+
+    public MockDataContext(String schemaName, String tableName, String value) {
+        _schemaName = schemaName;
+        _tableName = tableName;
+        _value = value;
+    }
+
+    @Override
+    protected Schema getMainSchema() throws MetaModelException {
+        
+        final MutableSchema schema = new MutableSchema(_schemaName);
+        final MutableTable primaryTable = new MutableTable(_tableName).setSchema(schema);
+        primaryTable.addColumn(new MutableColumn("foo").setColumnNumber(0).setType(ColumnType.VARCHAR).setTable(primaryTable));
+        primaryTable.addColumn(new MutableColumn("bar").setColumnNumber(1).setType(ColumnType.VARCHAR).setTable(primaryTable));
+        primaryTable.addColumn(new MutableColumn("baz").setColumnNumber(2).setType(ColumnType.VARCHAR).setTable(primaryTable));
+
+        final MutableTable emptyTable = new MutableTable("an_empty_table").setSchema(schema);
+        emptyTable.addColumn(new MutableColumn("foo").setColumnNumber(0).setType(ColumnType.VARCHAR).setTable(emptyTable));
+        emptyTable.addColumn(new MutableColumn("bar").setColumnNumber(1).setType(ColumnType.VARCHAR).setTable(emptyTable));
+        
+        schema.addTable(primaryTable);
+        schema.addTable(emptyTable);
+        
+        return schema;
+    }
+
+    @Override
+    protected String getMainSchemaName() throws MetaModelException {
+        return _schemaName;
+    }
+
+    @Override
+    protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) {
+        if (_tableName.equals(table.getName())) {
+            final SelectItem[] allSelectItems = MetaModelHelper.createSelectItems(table.getColumns());
+            final DataSetHeader header = new CachingDataSetHeader(allSelectItems);
+            final List<Row> data = new ArrayList<Row>();
+            data.add(new DefaultRow(header, new Object[] { "1", "hello", "world" }, null));
+            data.add(new DefaultRow(header, new Object[] { "2", _value, "world" }, null));
+            data.add(new DefaultRow(header, new Object[] { "3", "hi", _value }, null));
+            data.add(new DefaultRow(header, new Object[] { "4", "yo", "world" }, null));
+
+            DataSet ds = new InMemoryDataSet(header, data);
+
+            SelectItem[] columnSelectItems = MetaModelHelper.createSelectItems(columns);
+            ds = MetaModelHelper.getSelection(columnSelectItems, ds);
+
+            return ds;
+        } else if ("an_empty_table".equals(table.getName())) {
+            return new EmptyDataSet(columns);
+        }
+        throw new UnsupportedOperationException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/test/java/org/apache/metamodel/MockUpdateableDataContext.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/MockUpdateableDataContext.java b/core/src/test/java/org/apache/metamodel/MockUpdateableDataContext.java
new file mode 100644
index 0000000..f1b7f49
--- /dev/null
+++ b/core/src/test/java/org/apache/metamodel/MockUpdateableDataContext.java
@@ -0,0 +1,181 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eobjects.metamodel;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eobjects.metamodel.create.TableCreationBuilder;
+import org.eobjects.metamodel.data.CachingDataSetHeader;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.data.DefaultRow;
+import org.eobjects.metamodel.data.EmptyDataSet;
+import org.eobjects.metamodel.data.InMemoryDataSet;
+import org.eobjects.metamodel.data.Row;
+import org.eobjects.metamodel.delete.AbstractRowDeletionBuilder;
+import org.eobjects.metamodel.delete.RowDeletionBuilder;
+import org.eobjects.metamodel.drop.TableDropBuilder;
+import org.eobjects.metamodel.insert.AbstractRowInsertionBuilder;
+import org.eobjects.metamodel.insert.RowInsertionBuilder;
+import org.eobjects.metamodel.query.FilterItem;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.ColumnType;
+import org.eobjects.metamodel.schema.MutableColumn;
+import org.eobjects.metamodel.schema.MutableSchema;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+
+public class MockUpdateableDataContext extends QueryPostprocessDataContext implements UpdateableDataContext {
+
+    private final List<Object[]> _values = new ArrayList<Object[]>();
+
+    private final MutableTable _table;
+    private final MutableSchema _schema;
+
+    public MockUpdateableDataContext() {
+        _values.add(new Object[] { "1", "hello" });
+        _values.add(new Object[] { "2", "there" });
+        _values.add(new Object[] { "3", "world" });
+
+        _table = new MutableTable("table");
+        _table.addColumn(new MutableColumn("foo", ColumnType.VARCHAR).setTable(_table).setColumnNumber(0));
+        _table.addColumn(new MutableColumn("bar", ColumnType.VARCHAR).setTable(_table).setColumnNumber(1));
+        _schema = new MutableSchema("schema", _table);
+        _table.setSchema(_schema);
+    }
+
+    public MutableTable getTable() {
+        return _table;
+    }
+
+    @Override
+    protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) {
+
+        List<Row> rows = new ArrayList<Row>();
+        SelectItem[] items = MetaModelHelper.createSelectItems(columns);
+        CachingDataSetHeader header = new CachingDataSetHeader(items);
+
+        for (final Object[] values : _values) {
+            Object[] rowValues = new Object[columns.length];
+            for (int i = 0; i < columns.length; i++) {
+                int columnNumber = columns[i].getColumnNumber();
+                rowValues[i] = values[columnNumber];
+            }
+            rows.add(new DefaultRow(header, rowValues));
+        }
+
+        if (rows.isEmpty()) {
+            return new EmptyDataSet(items);
+        }
+        return new InMemoryDataSet(header, rows);
+    }
+
+    @Override
+    protected String getMainSchemaName() throws MetaModelException {
+        return _schema.getName();
+    }
+
+    @Override
+    protected Schema getMainSchema() throws MetaModelException {
+        return _schema;
+    }
+
+    @Override
+    public void executeUpdate(UpdateScript update) {
+        update.run(new AbstractUpdateCallback(this) {
+
+            @Override
+            public boolean isDeleteSupported() {
+                return true;
+            }
+
+            @Override
+            public RowDeletionBuilder deleteFrom(Table table) throws IllegalArgumentException, IllegalStateException,
+                    UnsupportedOperationException {
+                return new AbstractRowDeletionBuilder(table) {
+                    @Override
+                    public void execute() throws MetaModelException {
+                        delete(getWhereItems());
+                    }
+                };
+            }
+
+            @Override
+            public RowInsertionBuilder insertInto(Table table) throws IllegalArgumentException, IllegalStateException,
+                    UnsupportedOperationException {
+                return new AbstractRowInsertionBuilder<UpdateCallback>(this, table) {
+
+                    @Override
+                    public void execute() throws MetaModelException {
+                        Object[] values = toRow().getValues();
+                        _values.add(values);
+                    }
+                };
+            }
+
+            @Override
+            public boolean isDropTableSupported() {
+                return false;
+            }
+
+            @Override
+            public boolean isCreateTableSupported() {
+                return false;
+            }
+
+            @Override
+            public TableDropBuilder dropTable(Table table) throws IllegalArgumentException, IllegalStateException,
+                    UnsupportedOperationException {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public TableCreationBuilder createTable(Schema schema, String name) throws IllegalArgumentException,
+                    IllegalStateException {
+                throw new UnsupportedOperationException();
+            }
+        });
+    }
+
+    private void delete(List<FilterItem> whereItems) {
+        final SelectItem[] selectItems = MetaModelHelper.createSelectItems(_table.getColumns());
+        final CachingDataSetHeader header = new CachingDataSetHeader(selectItems);
+        for (Iterator<Object[]> it = _values.iterator(); it.hasNext();) {
+            Object[] values = (Object[]) it.next();
+            DefaultRow row = new DefaultRow(header, values);
+            boolean delete = true;
+            for (FilterItem filterItem : whereItems) {
+                if (!filterItem.evaluate(row)) {
+                    delete = false;
+                    break;
+                }
+            }
+            if (delete) {
+                it.remove();
+            }
+        }
+    }
+
+    public List<Object[]> getValues() {
+        return _values;
+    }
+}