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/22 10:10:56 UTC

[43/64] [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/main/java/org/apache/metamodel/query/builder/InitFromBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/InitFromBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/InitFromBuilder.java
new file mode 100644
index 0000000..fcbdbcf
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/InitFromBuilder.java
@@ -0,0 +1,39 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+
+/**
+ * The initial interface used when building a query. A query starts by stating
+ * the FROM clause.
+ * 
+ * @author Kasper Sørensen
+ */
+public interface InitFromBuilder {
+
+	public TableFromBuilder from(Table table);
+	
+	public TableFromBuilder from(Schema schema, String tableName);
+
+	public TableFromBuilder from(String schemaName, String tableName);
+
+	public TableFromBuilder from(String tableName);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/InitFromBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/InitFromBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/InitFromBuilderImpl.java
new file mode 100644
index 0000000..3d523a8
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/InitFromBuilderImpl.java
@@ -0,0 +1,89 @@
+/**
+ * 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.query.builder;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.util.BaseObject;
+
+public final class InitFromBuilderImpl extends BaseObject implements InitFromBuilder {
+
+    private DataContext dataContext;
+    private Query query;
+
+    public InitFromBuilderImpl(DataContext dataContext) {
+        this.dataContext = dataContext;
+        this.query = new Query();
+    }
+
+    @Override
+    public TableFromBuilder from(Table table) {
+        if (table == null) {
+            throw new IllegalArgumentException("table cannot be null");
+        }
+        return new TableFromBuilderImpl(table, query, dataContext);
+    }
+
+    @Override
+    public TableFromBuilder from(String schemaName, String tableName) {
+        if (schemaName == null) {
+            throw new IllegalArgumentException("schemaName cannot be null");
+        }
+        if (tableName == null) {
+            throw new IllegalArgumentException("tableName cannot be null");
+        }
+        Schema schema = dataContext.getSchemaByName(schemaName);
+        if (schema == null) {
+            schema = dataContext.getDefaultSchema();
+        }
+        return from(schema, tableName);
+    }
+
+    @Override
+    public TableFromBuilder from(Schema schema, String tableName) {
+        Table table = schema.getTableByName(tableName);
+        if (table == null) {
+            throw new IllegalArgumentException("Nu such table '" + tableName + "' found in schema: " + schema
+                    + ". Available tables are: " + Arrays.toString(schema.getTableNames()));
+        }
+        return from(table);
+    }
+
+    @Override
+    public TableFromBuilder from(String tableName) {
+        if (tableName == null) {
+            throw new IllegalArgumentException("tableName cannot be null");
+        }
+        Table table = dataContext.getTableByQualifiedLabel(tableName);
+        if (table == null) {
+            throw new IllegalArgumentException("No such table: " + tableName);
+        }
+        return from(table);
+    }
+
+    @Override
+    protected void decorateIdentity(List<Object> identifiers) {
+        identifiers.add(query);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilder.java
new file mode 100644
index 0000000..1cad5fc
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilder.java
@@ -0,0 +1,26 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.schema.Column;
+
+public interface JoinFromBuilder extends SatisfiedFromBuilder {
+
+	public SatisfiedFromBuilder on(Column left, Column right);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilderImpl.java
new file mode 100644
index 0000000..6e9520c
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/JoinFromBuilderImpl.java
@@ -0,0 +1,73 @@
+/**
+ * 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.query.builder;
+
+import java.util.List;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.query.FromItem;
+import org.eobjects.metamodel.query.JoinType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.Table;
+
+final class JoinFromBuilderImpl extends SatisfiedFromBuilderCallback implements
+		JoinFromBuilder {
+
+	private JoinType joinType;
+	private FromItem leftItem;
+	private FromItem rightItem;
+
+	public JoinFromBuilderImpl(Query query, FromItem leftItem,
+			Table rightTable, JoinType joinType, DataContext dataContext) {
+		super(query, dataContext);
+		this.joinType = joinType;
+		this.leftItem = leftItem;
+		this.rightItem = new FromItem(rightTable);
+	}
+
+	@Override
+	public SatisfiedFromBuilder on(Column left, Column right) {
+		if (left == null) {
+			throw new IllegalArgumentException("left cannot be null");
+		}
+		if (right == null) {
+			throw new IllegalArgumentException("right cannot be null");
+		}
+		getQuery().getFromClause().removeItem(leftItem);
+
+		SelectItem[] leftOn = new SelectItem[] { new SelectItem(left) };
+		SelectItem[] rightOn = new SelectItem[] { new SelectItem(right) };
+		FromItem fromItem = new FromItem(joinType, leftItem, rightItem, leftOn,
+				rightOn);
+
+		getQuery().from(fromItem);
+
+		return this;
+	}
+	
+	@Override
+	protected void decorateIdentity(List<Object> identifiers) {
+		super.decorateIdentity(identifiers);
+		identifiers.add(joinType);
+		identifiers.add(leftItem);
+		identifiers.add(rightItem);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilder.java
new file mode 100644
index 0000000..6cc2611
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilder.java
@@ -0,0 +1,52 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.Table;
+
+/**
+ * Represents a builder where the FROM part is satisfied, ie. a SELECT clause is
+ * now buildable.
+ * 
+ * @author Kasper Sørensen
+ */
+public interface SatisfiedFromBuilder {
+
+    public TableFromBuilder and(Table table);
+
+    public TableFromBuilder and(String schemaName, String tableName);
+
+    public TableFromBuilder and(String tableName);
+
+    public ColumnSelectBuilder<?> select(Column column);
+
+    public FunctionSelectBuilder<?> select(FunctionType functionType, Column column);
+
+    public CountSelectBuilder<?> selectCount();
+
+    public SatisfiedSelectBuilder<?> select(Column... columns);
+    
+    public SatisfiedSelectBuilder<?> selectAll();
+
+    public ColumnSelectBuilder<?> select(String columnName);
+
+    public SatisfiedSelectBuilder<?> select(String... columnNames);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilderCallback.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilderCallback.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilderCallback.java
new file mode 100644
index 0000000..d6798c2
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedFromBuilderCallback.java
@@ -0,0 +1,161 @@
+/**
+ * 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.query.builder;
+
+import java.util.List;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.util.BaseObject;
+
+abstract class SatisfiedFromBuilderCallback extends BaseObject implements SatisfiedFromBuilder {
+
+    private Query query;
+    private DataContext dataContext;
+
+    public SatisfiedFromBuilderCallback(Query query, DataContext dataContext) {
+        this.query = query;
+        this.dataContext = dataContext;
+    }
+
+    protected Query getQuery() {
+        return query;
+    }
+
+    protected DataContext getDataContext() {
+        return dataContext;
+    }
+
+    @Override
+    public TableFromBuilder and(Table table) {
+        if (table == null) {
+            throw new IllegalArgumentException("table cannot be null");
+        }
+
+        return new TableFromBuilderImpl(table, query, dataContext);
+    }
+
+    @Override
+    public ColumnSelectBuilder<?> select(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+
+        GroupedQueryBuilder queryBuilder = new GroupedQueryBuilderImpl(dataContext, query);
+        return new ColumnSelectBuilderImpl(column, query, queryBuilder);
+    }
+
+    @Override
+    public SatisfiedSelectBuilder<?> selectAll() {
+        getQuery().selectAll();
+        GroupedQueryBuilder queryBuilder = new GroupedQueryBuilderImpl(dataContext, query);
+        return new SatisfiedSelectBuilderImpl(queryBuilder);
+    }
+
+    @Override
+    public FunctionSelectBuilder<?> select(FunctionType functionType, Column column) {
+        if (functionType == null) {
+            throw new IllegalArgumentException("functionType cannot be null");
+        }
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+
+        GroupedQueryBuilder queryBuilder = new GroupedQueryBuilderImpl(dataContext, query);
+        return new FunctionSelectBuilderImpl(functionType, column, query, queryBuilder);
+    }
+
+    @Override
+    public CountSelectBuilder<?> selectCount() {
+        GroupedQueryBuilder queryBuilder = new GroupedQueryBuilderImpl(dataContext, query);
+        return new CountSelectBuilderImpl(query, queryBuilder);
+    }
+
+    @Override
+    public TableFromBuilder and(String schemaName, String tableName) {
+        if (schemaName == null) {
+            throw new IllegalArgumentException("schemaName cannot be null");
+        }
+        if (tableName == null) {
+            throw new IllegalArgumentException("tableName cannot be null");
+        }
+
+        Schema schema = dataContext.getSchemaByName(schemaName);
+        if (schema == null) {
+            schema = dataContext.getDefaultSchema();
+        }
+        return and(schema, tableName);
+    }
+
+    private TableFromBuilder and(Schema schema, String tableName) {
+        Table table = schema.getTableByName(tableName);
+        return and(table);
+    }
+
+    @Override
+    public TableFromBuilder and(String tableName) {
+        if (tableName == null) {
+            throw new IllegalArgumentException("tableName cannot be null");
+        }
+        return and(dataContext.getDefaultSchema(), tableName);
+    }
+
+    @Override
+    public SatisfiedSelectBuilder<?> select(Column... columns) {
+        if (columns == null) {
+            throw new IllegalArgumentException("columns cannot be null");
+        }
+        query.select(columns);
+        GroupedQueryBuilder queryBuilder = new GroupedQueryBuilderImpl(dataContext, query);
+        return new SatisfiedSelectBuilderImpl(queryBuilder);
+    }
+
+    @Override
+    public SatisfiedSelectBuilder<?> select(String... columnNames) {
+        if (columnNames == null) {
+            throw new IllegalArgumentException("columnNames cannot be null");
+        }
+        for (String columnName : columnNames) {
+            select(columnName);
+        }
+        GroupedQueryBuilder queryBuilder = new GroupedQueryBuilderImpl(dataContext, query);
+        return new SatisfiedSelectBuilderImpl(queryBuilder);
+    }
+
+    @Override
+    public ColumnSelectBuilder<?> select(String columnName) {
+        if (columnName == null) {
+            throw new IllegalArgumentException("columnName cannot be null");
+        }
+
+        GroupedQueryBuilderImpl queryBuilder = new GroupedQueryBuilderImpl(dataContext, query);
+        Column column = queryBuilder.findColumn(columnName);
+        return select(column);
+    }
+
+    @Override
+    protected void decorateIdentity(List<Object> identifiers) {
+        identifiers.add(query);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedHavingBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedHavingBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedHavingBuilder.java
new file mode 100644
index 0000000..b5c6efe
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedHavingBuilder.java
@@ -0,0 +1,29 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.schema.Column;
+
+public interface SatisfiedHavingBuilder extends GroupedQueryBuilder {
+
+	public HavingBuilder or(FunctionType functionType, Column column);
+
+	public HavingBuilder and(FunctionType functionType, Column column);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilder.java
new file mode 100644
index 0000000..a7023cf
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilder.java
@@ -0,0 +1,31 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.schema.Column;
+
+public interface SatisfiedOrderByBuilder<B extends SatisfiedQueryBuilder<?>>
+		extends SatisfiedQueryBuilder<B> {
+
+	public B asc();
+
+	public B desc();
+
+	public SatisfiedOrderByBuilder<B> and(Column column);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilderImpl.java
new file mode 100644
index 0000000..5ebe755
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedOrderByBuilderImpl.java
@@ -0,0 +1,64 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.query.OrderByItem;
+import org.eobjects.metamodel.query.OrderByItem.Direction;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+final class SatisfiedOrderByBuilderImpl extends GroupedQueryBuilderCallback
+		implements SatisfiedOrderByBuilder<GroupedQueryBuilder> {
+
+	private OrderByItem orderByitem;
+
+	public SatisfiedOrderByBuilderImpl(Column column, Query query,
+			GroupedQueryBuilder queryBuilder) {
+		super(queryBuilder);
+		orderByitem = new OrderByItem(new SelectItem(column));
+		query.orderBy(orderByitem);
+	}
+
+	public SatisfiedOrderByBuilderImpl(FunctionType function, Column column,
+			Query query, GroupedQueryBuilder queryBuilder) {
+		super(queryBuilder);
+		orderByitem = new OrderByItem(new SelectItem(function, column));
+		query.orderBy(orderByitem);
+	}
+
+	@Override
+	public GroupedQueryBuilder asc() {
+		orderByitem.setDirection(Direction.ASC);
+		return getQueryBuilder();
+	}
+
+	@Override
+	public GroupedQueryBuilder desc() {
+		orderByitem.setDirection(Direction.DESC);
+		return getQueryBuilder();
+	}
+	
+	@Override
+	public SatisfiedOrderByBuilder<GroupedQueryBuilder> and(Column column) {
+		return getQueryBuilder().orderBy(column);
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedQueryBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedQueryBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedQueryBuilder.java
new file mode 100644
index 0000000..dd98935
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedQueryBuilder.java
@@ -0,0 +1,133 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.query.CompiledQuery;
+import org.eobjects.metamodel.query.FilterItem;
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.schema.Column;
+
+/**
+ * Represents a built query that is satisfied and ready for querying or further
+ * building.
+ * 
+ * @author Kasper Sørensen
+ * 
+ * @param <B>
+ */
+public interface SatisfiedQueryBuilder<B extends SatisfiedQueryBuilder<?>> {
+
+    public ColumnSelectBuilder<B> select(Column column);
+
+    public SatisfiedSelectBuilder<B> select(Column... columns);
+
+    /**
+     * Sets the offset (number of rows to skip) of the query that is being
+     * built.
+     * 
+     * Note that this number is a 0-based variant of invoking
+     * {@link #firstRow(int)}.
+     * 
+     * @param offset
+     *            the number of rows to skip
+     * @return
+     */
+    public SatisfiedQueryBuilder<B> offset(int offset);
+
+    /**
+     * Sets the first row of the query that is being built.
+     * 
+     * Note that this is a 1-based variant of invoking {@link #limit(int)}.
+     * 
+     * @param firstRow
+     * @return
+     */
+    public SatisfiedQueryBuilder<B> firstRow(int firstRow);
+
+    /**
+     * Sets the limit (aka. max rows) of the query that is being built.
+     * 
+     * @param maxRows
+     * @return
+     */
+    public SatisfiedQueryBuilder<B> limit(int limit);
+
+    /**
+     * Sets the max rows (aka. limit) of the query that is being built.
+     * 
+     * @param maxRows
+     * @return
+     */
+    public SatisfiedQueryBuilder<B> maxRows(int maxRows);
+
+    public FunctionSelectBuilder<B> select(FunctionType functionType, Column column);
+
+    public CountSelectBuilder<B> selectCount();
+
+    public ColumnSelectBuilder<B> select(String columnName);
+
+    public WhereBuilder<B> where(Column column);
+
+    public WhereBuilder<B> where(String columnName);
+
+    public SatisfiedQueryBuilder<B> where(FilterItem... filters);
+
+    public SatisfiedQueryBuilder<B> where(Iterable<FilterItem> filters);
+
+    public SatisfiedOrderByBuilder<B> orderBy(String columnName);
+
+    public SatisfiedOrderByBuilder<B> orderBy(Column column);
+
+    public GroupedQueryBuilder groupBy(String columnName);
+
+    public GroupedQueryBuilder groupBy(Column column);
+
+    public B groupBy(Column... columns);
+
+    /**
+     * Gets the built query as a {@link Query} object. Typically the returned
+     * query will be a clone of the built query to prevent conflicting
+     * mutations.
+     * 
+     * @return a {@link Query} object representing the built query.
+     */
+    public Query toQuery();
+
+    public CompiledQuery compile();
+
+    /**
+     * Executes the built query. This call is similar to calling
+     * {@link #toQuery()} and then {@link DataContext#executeQuery(Query)}.
+     * 
+     * @return the {@link DataSet} that is returned by executing the query.
+     */
+    public DataSet execute();
+
+    /**
+     * Finds a column by name within the already defined FROM items
+     * 
+     * @param columnName
+     * @return
+     * @throws IllegalArgumentException
+     */
+    public Column findColumn(String columnName) throws IllegalArgumentException;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilder.java
new file mode 100644
index 0000000..886b763
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilder.java
@@ -0,0 +1,35 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.schema.Column;
+
+public interface SatisfiedSelectBuilder<B extends SatisfiedQueryBuilder<?>>
+		extends SatisfiedQueryBuilder<B> {
+	
+	public ColumnSelectBuilder<B> and(Column column);
+
+	public SatisfiedSelectBuilder<B> and(Column ... columns);
+
+	public FunctionSelectBuilder<B> and(FunctionType function,
+			Column column);
+	
+	public SatisfiedSelectBuilder<B> and(String columnName);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilderImpl.java
new file mode 100644
index 0000000..2fe66ce
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedSelectBuilderImpl.java
@@ -0,0 +1,67 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.schema.Column;
+
+class SatisfiedSelectBuilderImpl extends GroupedQueryBuilderCallback implements
+		SatisfiedSelectBuilder<GroupedQueryBuilder> {
+
+	public SatisfiedSelectBuilderImpl(GroupedQueryBuilder queryBuilder) {
+		super(queryBuilder);
+	}
+
+	@Override
+	public ColumnSelectBuilder<GroupedQueryBuilder> and(Column column) {
+		if (column == null) {
+			throw new IllegalArgumentException("column cannot be null");
+		}
+		return getQueryBuilder().select(column);
+	}
+
+	@Override
+	public SatisfiedSelectBuilder<GroupedQueryBuilder> and(Column... columns) {
+		if (columns == null) {
+			throw new IllegalArgumentException("columns cannot be null");
+		}
+		return getQueryBuilder().select(columns);
+	}
+
+	@Override
+	public FunctionSelectBuilder<GroupedQueryBuilder> and(
+			FunctionType functionType, Column column) {
+		if (functionType == null) {
+			throw new IllegalArgumentException("functionType cannot be null");
+		}
+		if (column == null) {
+			throw new IllegalArgumentException("column cannot be null");
+		}
+		return getQueryBuilder().select(functionType, column);
+	}
+
+	@Override
+	public SatisfiedSelectBuilder<GroupedQueryBuilder> and(String columnName) {
+		if (columnName == null) {
+			throw new IllegalArgumentException("columnName cannot be null");
+		}
+		return getQueryBuilder().select(columnName);
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedWhereBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedWhereBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedWhereBuilder.java
new file mode 100644
index 0000000..d236ed2
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/SatisfiedWhereBuilder.java
@@ -0,0 +1,33 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.schema.Column;
+
+public interface SatisfiedWhereBuilder<B extends SatisfiedQueryBuilder<?>>
+		extends SatisfiedQueryBuilder<B> {
+    
+    public WhereBuilder<B> or(String columnName);
+
+	public WhereBuilder<B> or(Column column);
+	
+	public WhereBuilder<B> and(String columnName);
+	
+	public WhereBuilder<B> and(Column column);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilder.java
new file mode 100644
index 0000000..d030653
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilder.java
@@ -0,0 +1,33 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.schema.Table;
+
+public interface TableFromBuilder extends
+		SatisfiedFromBuilder {
+
+	public JoinFromBuilder innerJoin(Table table);
+	
+	public JoinFromBuilder leftJoin(Table table);
+	
+	public JoinFromBuilder rightJoin(Table table);
+
+	public TableFromBuilder as(String alias);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilderImpl.java
new file mode 100644
index 0000000..4460d8e
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/TableFromBuilderImpl.java
@@ -0,0 +1,83 @@
+/**
+ * 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.query.builder;
+
+import java.util.List;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.query.FromItem;
+import org.eobjects.metamodel.query.JoinType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.schema.Table;
+
+final class TableFromBuilderImpl extends SatisfiedFromBuilderCallback implements
+		TableFromBuilder {
+
+	private FromItem fromItem;
+
+	public TableFromBuilderImpl(Table table, Query query,
+			DataContext dataContext) {
+		super(query, dataContext);
+
+		fromItem = new FromItem(table);
+		query.from(fromItem);
+	}
+
+	@Override
+	public JoinFromBuilder innerJoin(Table table) {
+		if (table == null) {
+			throw new IllegalArgumentException("table cannot be null");
+		}
+		return new JoinFromBuilderImpl(getQuery(), fromItem, table,
+				JoinType.INNER, getDataContext());
+	}
+
+	@Override
+	public JoinFromBuilder leftJoin(Table table) {
+		if (table == null) {
+			throw new IllegalArgumentException("table cannot be null");
+		}
+		return new JoinFromBuilderImpl(getQuery(), fromItem, table,
+				JoinType.LEFT, getDataContext());
+	}
+
+	@Override
+	public JoinFromBuilder rightJoin(Table table) {
+		if (table == null) {
+			throw new IllegalArgumentException("table cannot be null");
+		}
+		return new JoinFromBuilderImpl(getQuery(), fromItem, table,
+				JoinType.RIGHT, getDataContext());
+	}
+
+	@Override
+	public TableFromBuilder as(String alias) {
+		if (alias == null) {
+			throw new IllegalArgumentException("alias cannot be null");
+		}
+		fromItem.setAlias(alias);
+		return this;
+	}
+
+	@Override
+	protected void decorateIdentity(List<Object> identifiers) {
+		super.decorateIdentity(identifiers);
+		identifiers.add(fromItem);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilder.java
new file mode 100644
index 0000000..3055214
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilder.java
@@ -0,0 +1,86 @@
+/**
+ * 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.query.builder;
+
+import org.eobjects.metamodel.query.CompiledQuery;
+import org.eobjects.metamodel.query.QueryParameter;
+
+/**
+ * Builder interface for WHERE items.
+ * 
+ * In addition to the {@link FilterBuilder}, the WHERE builder allows using
+ * {@link QueryParameter}s as operands in the generated filters.
+ * 
+ * @param <B>
+ */
+public interface WhereBuilder<B extends SatisfiedQueryBuilder<?>> extends FilterBuilder<SatisfiedWhereBuilder<B>> {
+
+    /**
+     * Equals to a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> eq(QueryParameter queryParameter);
+
+    /**
+     * Equals to a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> isEquals(QueryParameter queryParameter);
+
+    /**
+     * Not equals to a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> differentFrom(QueryParameter queryParameter);
+
+    /**
+     * Not equals to a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> ne(QueryParameter queryParameter);
+
+    /**
+     * Greater than a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> greaterThan(QueryParameter queryParameter);
+
+    /**
+     * Greater than a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> gt(QueryParameter queryParameter);
+
+    /**
+     * Less than a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> lessThan(QueryParameter queryParameter);
+
+    /**
+     * Less than a query parameter. Can be used with {@link CompiledQuery}
+     * objects.
+     */
+    public SatisfiedWhereBuilder<B> lt(QueryParameter queryParameter);
+
+    /**
+     * Like a query parameter. Can be used with {@link CompiledQuery} objects.
+     */
+    public SatisfiedWhereBuilder<B> like(QueryParameter queryParameter);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilderImpl.java
new file mode 100644
index 0000000..7e1db14
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/WhereBuilderImpl.java
@@ -0,0 +1,151 @@
+/**
+ * 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.query.builder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eobjects.metamodel.query.FilterItem;
+import org.eobjects.metamodel.query.OperatorType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.QueryParameter;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+final class WhereBuilderImpl extends AbstractQueryFilterBuilder<SatisfiedWhereBuilder<GroupedQueryBuilder>> implements
+        WhereBuilder<GroupedQueryBuilder>, SatisfiedWhereBuilder<GroupedQueryBuilder> {
+
+    private final Query _query;
+    private final List<FilterItem> _orFilters;
+    private FilterItem _parentOrFilter;
+
+    public WhereBuilderImpl(Column column, Query query, GroupedQueryBuilder queryBuilder) {
+        super(new SelectItem(column), queryBuilder);
+        _query = query;
+        _orFilters = new ArrayList<FilterItem>();
+    }
+
+    public WhereBuilderImpl(Column column, Query query, FilterItem parentOrFilter, List<FilterItem> orFilters,
+            GroupedQueryBuilder queryBuilder) {
+        super(new SelectItem(column), queryBuilder);
+        _query = query;
+        _parentOrFilter = parentOrFilter;
+        _orFilters = orFilters;
+    }
+
+    @Override
+    protected SatisfiedWhereBuilder<GroupedQueryBuilder> applyFilter(FilterItem filter) {
+        if (_parentOrFilter == null) {
+            _query.where(filter);
+        } else {
+            if (_parentOrFilter.getChildItemCount() == 1) {
+                _query.getWhereClause().removeItem(_orFilters.get(0));
+                _query.getWhereClause().addItem(_parentOrFilter);
+            }
+        }
+        _orFilters.add(filter);
+        return this;
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> or(String columnName) {
+        Column column = findColumn(columnName);
+        return or(column);
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> or(Column column) {
+        if (_parentOrFilter == null) {
+            _parentOrFilter = new FilterItem(_orFilters);
+        }
+        return new WhereBuilderImpl(column, _query, _parentOrFilter, _orFilters, getQueryBuilder());
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> and(String columnName) {
+        Column column = findColumn(columnName);
+        return and(column);
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> and(Column column) {
+        return getQueryBuilder().where(column);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> eq(QueryParameter queryParameter) {
+        return isEquals(queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> isEquals(QueryParameter queryParameter) {
+        if (queryParameter == null) {
+            throw new IllegalArgumentException("query parameter cannot be null");
+        }
+        return _filterBuilder.applyFilter(OperatorType.EQUALS_TO, queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> differentFrom(QueryParameter queryParameter) {
+        return ne(queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> ne(QueryParameter queryParameter) {
+        if (queryParameter == null) {
+            throw new IllegalArgumentException("query parameter cannot be null");
+        }
+        return _filterBuilder.applyFilter(OperatorType.DIFFERENT_FROM, queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> greaterThan(QueryParameter queryParameter) {
+        return gt(queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> gt(QueryParameter queryParameter) {
+        if (queryParameter == null) {
+            throw new IllegalArgumentException("query parameter cannot be null");
+        }
+        return _filterBuilder.applyFilter(OperatorType.GREATER_THAN, queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> lessThan(QueryParameter queryParameter) {
+        return lt(queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> lt(QueryParameter queryParameter) {
+        if (queryParameter == null) {
+            throw new IllegalArgumentException("query parameter cannot be null");
+        }
+        return _filterBuilder.applyFilter(OperatorType.LESS_THAN, queryParameter);
+    }
+
+    @Override
+    public SatisfiedWhereBuilder<GroupedQueryBuilder> like(QueryParameter queryParameter) {
+        if (queryParameter == null) {
+            throw new IllegalArgumentException("query parameter cannot be null");
+        }
+        return _filterBuilder.applyFilter(OperatorType.LIKE, queryParameter);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/package-info.java b/core/src/main/java/org/apache/metamodel/query/builder/package-info.java
new file mode 100644
index 0000000..87e58db
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+/**
+ * API for query building
+ */
+package org.eobjects.metamodel.query.builder;
+

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/package-info.java b/core/src/main/java/org/apache/metamodel/query/package-info.java
new file mode 100644
index 0000000..f71ce82
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+/**
+ * API for querying
+ */
+package org.eobjects.metamodel.query;
+

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java b/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java
new file mode 100644
index 0000000..78fff2e
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java
@@ -0,0 +1,173 @@
+/**
+ * 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.query.parser;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.query.FromItem;
+import org.eobjects.metamodel.query.JoinType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Table;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class FromItemParser implements QueryPartProcessor {
+
+    private static final Logger logger = LoggerFactory.getLogger(FromItemParser.class);
+
+    private final Query _query;
+    private final DataContext _dataContext;
+
+    public FromItemParser(DataContext dataContext, Query query) {
+        _dataContext = dataContext;
+        _query = query;
+    }
+
+    @Override
+    public void parse(String delim, String itemToken) {
+        final FromItem fromItem;
+
+        final int parenthesisStart = itemToken.indexOf('(');
+        if (parenthesisStart != -1) {
+            if (parenthesisStart != 0) {
+                throw new QueryParserException("Not capable of parsing FROM token: " + itemToken
+                        + ". Expected parenthesis to start at first character.");
+            }
+            final int parenthesisEnd = itemToken.indexOf(')', parenthesisStart);
+            if (parenthesisEnd == -1) {
+                throw new QueryParserException("Not capable of parsing FROM token: " + itemToken
+                        + ". Expected end parenthesis.");
+            }
+
+            final String subQueryString = itemToken.substring(parenthesisStart + 1, parenthesisEnd);
+            logger.debug("Parsing sub-query: {}", subQueryString);
+
+            final Query subQuery = new QueryParser(_dataContext, subQueryString).parse();
+            fromItem = new FromItem(subQuery);
+
+            final String alias = itemToken.substring(parenthesisEnd + 1).trim();
+            if (!alias.isEmpty()) {
+                fromItem.setAlias(alias);
+            }
+        } else if (itemToken.toUpperCase().indexOf(" JOIN ") != -1) {
+            fromItem = parseJoinItem(itemToken);
+        } else {
+            fromItem = parseTableItem(itemToken);
+        }
+
+        _query.from(fromItem);
+    }
+
+    private FromItem parseTableItem(String itemToken) {
+        final String[] tokens = itemToken.split(" ");
+        final String alias;
+        if (tokens.length == 2) {
+            alias = tokens[1];
+        } else if (tokens.length == 1) {
+            alias = null;
+        } else {
+            throw new QueryParserException("Not capable of parsing FROM token: " + itemToken);
+        }
+
+        final Table table = _dataContext.getTableByQualifiedLabel(tokens[0]);
+        if (table == null) {
+            throw new QueryParserException("Not capable of parsing FROM token: " + itemToken);
+        }
+
+        final FromItem result = new FromItem(table);
+        result.setAlias(alias);
+        result.setQuery(_query);
+        return result;
+    }
+
+    // this method will be documented based on this example itemToken: FOO f
+    // INNER JOIN BAR b ON f.id = b.id
+    private FromItem parseJoinItem(final String itemToken) {
+        final int indexOfJoin = itemToken.toUpperCase().indexOf(" JOIN ");
+
+        // firstPart = "FOO f INNER"
+        final String firstPart = itemToken.substring(0, indexOfJoin).trim();
+
+        // secondPart = "BAR b ON f.id = b.id"
+        final String secondPart = itemToken.substring(indexOfJoin + " JOIN ".length()).trim();
+
+        final int indexOfJoinType = firstPart.lastIndexOf(" ");
+
+        // joinTypeString = "INNER"
+        final String joinTypeString = firstPart.substring(indexOfJoinType).trim().toUpperCase();
+        final JoinType joinType = JoinType.valueOf(joinTypeString);
+
+        // firstTableToken = "FOO f"
+        final String firstTableToken = firstPart.substring(0, indexOfJoinType).trim();
+
+        final int indexOfOn = secondPart.toUpperCase().indexOf(" ON ");
+
+        // secondTableToken = "BAR b"
+        final String secondTableToken = secondPart.substring(0, indexOfOn).trim();
+
+        final FromItem leftSide = parseTableItem(firstTableToken);
+        final FromItem rightSide = parseTableItem(secondTableToken);
+
+        // onClausess = ["f.id = b.id"]
+        final String[] onClauses = secondPart.substring(indexOfOn + " ON ".length()).split(" AND ");
+        final SelectItem[] leftOn = new SelectItem[onClauses.length];
+        final SelectItem[] rightOn = new SelectItem[onClauses.length];
+        for (int i = 0; i < onClauses.length; i++) {
+            final String onClause = onClauses[i];
+            final int indexOfEquals = onClause.indexOf("=");
+            // leftPart = "f.id"
+            final String leftPart = onClause.substring(0, indexOfEquals).trim();
+            // rightPart = "b.id"
+            final String rightPart = onClause.substring(indexOfEquals + 1).trim();
+
+            leftOn[i] = findSelectItem(leftPart, leftSide, rightSide);
+            rightOn[i] = findSelectItem(rightPart, leftSide, rightSide);
+        }
+
+        final FromItem result = new FromItem(joinType, leftSide, rightSide, leftOn, rightOn);
+        result.setQuery(_query);
+        return result;
+    }
+
+    private SelectItem findSelectItem(String token, FromItem leftSide, FromItem rightSide) {
+        // first look in the original query
+        SelectItemParser selectItemParser = new SelectItemParser(_query, false);
+        SelectItem result = selectItemParser.findSelectItem(token);
+
+        if (result == null) {
+            // fail over and try with the from items available in the join that
+            // is being built.
+            final Query temporaryQuery = new Query().from(leftSide, rightSide);
+            selectItemParser = new SelectItemParser(temporaryQuery, false);
+            result = selectItemParser.findSelectItem(token);
+
+            if (result == null) {
+                throw new QueryParserException("Not capable of parsing ON token: " + token);
+            }
+
+            // set the query on the involved query parts (since they have been
+            // temporarily moved to the searched query).
+            leftSide.setQuery(_query);
+            rightSide.setQuery(_query);
+            result.setQuery(_query);
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/GroupByItemParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/GroupByItemParser.java b/core/src/main/java/org/apache/metamodel/query/parser/GroupByItemParser.java
new file mode 100644
index 0000000..fc7e776
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/GroupByItemParser.java
@@ -0,0 +1,36 @@
+/**
+ * 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.query.parser;
+
+import org.eobjects.metamodel.query.Query;
+
+final class GroupByItemParser implements QueryPartProcessor {
+
+    private final Query _query;
+
+    public GroupByItemParser(Query query) {
+        _query = query;
+    }
+
+    @Override
+    public void parse(String delim, String itemToken) {
+        _query.groupBy(itemToken);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/HavingItemParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/HavingItemParser.java b/core/src/main/java/org/apache/metamodel/query/parser/HavingItemParser.java
new file mode 100644
index 0000000..5f4a559
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/HavingItemParser.java
@@ -0,0 +1,36 @@
+/**
+ * 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.query.parser;
+
+import org.eobjects.metamodel.query.Query;
+
+final class HavingItemParser implements QueryPartProcessor {
+
+    private final Query _query;
+
+    public HavingItemParser(Query query) {
+        _query = query;
+    }
+
+    @Override
+    public void parse(String delim, String itemToken) {
+        _query.having(itemToken);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/OrderByItemParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/OrderByItemParser.java b/core/src/main/java/org/apache/metamodel/query/parser/OrderByItemParser.java
new file mode 100644
index 0000000..8c3ebf0
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/OrderByItemParser.java
@@ -0,0 +1,36 @@
+/**
+ * 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.query.parser;
+
+import org.eobjects.metamodel.query.Query;
+
+final class OrderByItemParser implements QueryPartProcessor {
+
+    private final Query _query;
+
+    public OrderByItemParser(Query query) {
+        _query = query;
+    }
+
+    @Override
+    public void parse(String delim, String itemToken) {
+        _query.orderBy(itemToken);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/QueryParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/QueryParser.java b/core/src/main/java/org/apache/metamodel/query/parser/QueryParser.java
new file mode 100644
index 0000000..a5f0e03
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/QueryParser.java
@@ -0,0 +1,264 @@
+/**
+ * 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.query.parser;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.query.Query;
+
+/**
+ * A parser class of for full SQL-like queries.
+ */
+public class QueryParser {
+
+    private final DataContext _dataContext;
+    private final String _queryString;
+    private final String _queryStringUpperCase;
+
+    public QueryParser(DataContext dataContext, String queryString) {
+        if (dataContext == null) {
+            throw new IllegalArgumentException("DataContext cannot be null");
+        }
+        if (queryString == null) {
+            throw new IllegalArgumentException("Query string cannot be null");
+        }
+        _dataContext = dataContext;
+        _queryString = prepareQuery(queryString);
+        _queryStringUpperCase = _queryString.toUpperCase();
+    }
+
+    /**
+     * Performs any preparations (not changing any semantics) to the query
+     * string
+     * 
+     * @param queryString
+     * @return
+     */
+    private String prepareQuery(String queryString) {
+        queryString = queryString.replaceAll("[\n\r\t]", " ");
+        queryString = queryString.replaceAll("  ", " ");
+        queryString = queryString.trim();
+        return queryString;
+    }
+
+    public Query parse() throws QueryParserException {
+        final Query query = new Query();
+
+        // collect focal point query clauses
+        int[] selectIndices = indexesOf("SELECT ", null);
+        int[] fromIndices = indexesOf(" FROM ", selectIndices);
+        int[] whereIndices = indexesOf(" WHERE ", fromIndices);
+        int[] groupByIndices = indexesOf(" GROUP BY ", whereIndices);
+        int[] havingIndices = indexesOf(" HAVING ", groupByIndices);
+        int[] orderByIndices = indexesOf(" ORDER BY", havingIndices);
+        int[] limitIndices = indexesOf(" LIMIT ", orderByIndices);
+        int[] offsetIndices = indexesOf(" OFFSET ", limitIndices);
+
+        // a few validations, minimum requirements
+        if (selectIndices == null) {
+            throw new QueryParserException("SELECT not found in query: " + _queryString);
+        }
+        if (fromIndices == null) {
+            throw new QueryParserException("FROM not found in query: " + _queryString);
+        }
+
+        // parse FROM
+        {
+            final String fromClause = getSubstring(
+                    getLastEndIndex(fromIndices),
+                    getNextStartIndex(whereIndices, groupByIndices, havingIndices, orderByIndices, limitIndices,
+                            offsetIndices));
+            parseFromClause(query, fromClause);
+        }
+
+        {
+            String selectClause = getSubstring(getLastEndIndex(selectIndices), fromIndices[0]);
+            if (selectClause.startsWith("DISTINCT ")) {
+                query.selectDistinct();
+                selectClause = selectClause.substring("DISTINCT ".length());
+            }
+            parseSelectClause(query, selectClause);
+        }
+
+        if (whereIndices != null) {
+            final String whereClause = getSubstring(getLastEndIndex(whereIndices),
+                    getNextStartIndex(groupByIndices, havingIndices, orderByIndices, limitIndices, offsetIndices));
+            if (whereClause != null) {
+                parseWhereClause(query, whereClause);
+            }
+        }
+
+        if (groupByIndices != null) {
+            final String groupByClause = getSubstring(getLastEndIndex(groupByIndices, whereIndices),
+                    getNextStartIndex(havingIndices, orderByIndices, limitIndices, offsetIndices));
+            if (groupByClause != null) {
+                parseGroupByClause(query, groupByClause);
+            }
+        }
+
+        if (havingIndices != null) {
+            final String havingClause = getSubstring(
+                    getLastEndIndex(havingIndices, groupByIndices, whereIndices, fromIndices, selectIndices),
+                    getNextStartIndex(orderByIndices, limitIndices, offsetIndices));
+            if (havingClause != null) {
+                parseHavingClause(query, havingClause);
+            }
+        }
+
+        if (orderByIndices != null) {
+            final String orderByClause = getSubstring(
+                    getLastEndIndex(orderByIndices, havingIndices, groupByIndices, whereIndices, fromIndices,
+                            selectIndices), getNextStartIndex(limitIndices, offsetIndices));
+            if (orderByClause != null) {
+                parseOrderByClause(query, orderByClause);
+            }
+        }
+
+        if (limitIndices != null) {
+            final String limitClause = getSubstring(
+                    getLastEndIndex(limitIndices, orderByIndices, havingIndices, groupByIndices, whereIndices,
+                            fromIndices, selectIndices), getNextStartIndex(offsetIndices));
+            if (limitClause != null) {
+                parseLimitClause(query, limitClause);
+            }
+        }
+
+        if (offsetIndices != null) {
+            final String offsetClause = getSubstring(
+                    getLastEndIndex(offsetIndices, limitIndices, orderByIndices, havingIndices, groupByIndices,
+                            whereIndices, fromIndices, selectIndices), getNextStartIndex());
+            if (offsetClause != null) {
+                parseOffsetClause(query, offsetClause);
+            }
+        }
+
+        return query;
+    }
+
+    private void parseFromClause(Query query, String fromClause) {
+        QueryPartParser clauseParser = new QueryPartParser(new FromItemParser(_dataContext, query), fromClause, ",");
+        clauseParser.parse();
+    }
+
+    private void parseSelectClause(Query query, String selectClause) {
+        QueryPartParser clauseParser = new QueryPartParser(new SelectItemParser(query, false), selectClause, ",");
+        clauseParser.parse();
+    }
+
+    private void parseWhereClause(Query query, String whereClause) {
+        // only parse "AND" delimitors, since "OR" will be taken care of as
+        // compound filter items at 2nd level parsing
+        QueryPartParser clauseParser = new QueryPartParser(new WhereItemParser(query), whereClause, " AND ");
+        clauseParser.parse();
+    }
+
+    private void parseGroupByClause(Query query, String groupByClause) {
+        QueryPartParser clauseParser = new QueryPartParser(new GroupByItemParser(query), groupByClause, ",");
+        clauseParser.parse();
+    }
+
+    private void parseHavingClause(Query query, String havingClause) {
+        // only parse "AND" delimitors, since "OR" will be taken care of as
+        // compound filter items at 2nd level parsing
+        QueryPartParser clauseParser = new QueryPartParser(new HavingItemParser(query), havingClause, " AND ");
+        clauseParser.parse();
+    }
+
+    private void parseOrderByClause(Query query, String orderByClause) {
+        QueryPartParser clauseParser = new QueryPartParser(new OrderByItemParser(query), orderByClause, ",");
+        clauseParser.parse();
+    }
+
+    private void parseLimitClause(Query query, String limitClause) {
+        limitClause = limitClause.trim();
+        if (!limitClause.isEmpty()) {
+            try {
+                int limit = Integer.parseInt(limitClause);
+                query.setMaxRows(limit);
+            } catch (NumberFormatException e) {
+                throw new QueryParserException("Could not parse LIMIT value: " + limitClause);
+            }
+        }
+    }
+
+    private void parseOffsetClause(Query query, String offsetClause) {
+        offsetClause = offsetClause.trim();
+        if (!offsetClause.isEmpty()) {
+            try {
+                final int offset = Integer.parseInt(offsetClause);
+                // ofset is 0-based, but first-row is 1-based
+                final int firstRow = offset + 1;
+                query.setFirstRow(firstRow);
+            } catch (NumberFormatException e) {
+                throw new QueryParserException("Could not parse OFFSET value: " + offsetClause);
+            }
+        }
+    }
+
+    private String getSubstring(Integer from, int to) {
+        if (from == null) {
+            return null;
+        }
+        if (from.intValue() == to) {
+            return null;
+        }
+        return _queryString.substring(from, to);
+    }
+
+    private int getNextStartIndex(int[]... indicesArray) {
+        for (int[] indices : indicesArray) {
+            if (indices != null) {
+                return indices[0];
+            }
+        }
+        return _queryString.length();
+    }
+
+    private Integer getLastEndIndex(int[]... indicesArray) {
+        for (int[] indices : indicesArray) {
+            if (indices != null) {
+                return indices[1];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds the start and end indexes of a string in the query. The string
+     * parameter of this method is expected to be in upper case, while the query
+     * itself is tolerant of case differences.
+     * 
+     * @param string
+     * @param previousIndices
+     * @return
+     */
+    protected int[] indexesOf(String string, int[] previousIndices) {
+        final int startIndex;
+        if (previousIndices == null) {
+            startIndex = _queryStringUpperCase.indexOf(string);
+        } else {
+            startIndex = _queryStringUpperCase.indexOf(string, previousIndices[1]);
+        }
+        if (startIndex == -1) {
+            return null;
+        }
+        int endIndex = startIndex + string.length();
+        return new int[] { startIndex, endIndex };
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/QueryParserException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/QueryParserException.java b/core/src/main/java/org/apache/metamodel/query/parser/QueryParserException.java
new file mode 100644
index 0000000..ad3f42c
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/QueryParserException.java
@@ -0,0 +1,46 @@
+/**
+ * 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.query.parser;
+
+import org.eobjects.metamodel.MetaModelException;
+
+/**
+ * Subtype of {@link MetaModelException} which indicate a problem in parsing a
+ * query passed to the {@link QueryParser}.
+ */
+public class QueryParserException extends MetaModelException {
+
+    private static final long serialVersionUID = 1L;
+
+    public QueryParserException() {
+        super();
+    }
+
+    public QueryParserException(Exception cause) {
+        super(cause);
+    }
+
+    public QueryParserException(String message, Exception cause) {
+        super(message, cause);
+    }
+
+    public QueryParserException(String message) {
+        super(message);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/QueryPartCollectionProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/QueryPartCollectionProcessor.java b/core/src/main/java/org/apache/metamodel/query/parser/QueryPartCollectionProcessor.java
new file mode 100644
index 0000000..ac45a49
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/QueryPartCollectionProcessor.java
@@ -0,0 +1,52 @@
+/**
+ * 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.query.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Simple implementation of {@link QueryPartProcessor} which simply adds all
+ * elements to a collection. Use {@link #getTokens()} to retrieve the 'processed'
+ * tokens and {@link #getDelims()} for the corresponding delimitors.
+ */
+public class QueryPartCollectionProcessor implements QueryPartProcessor {
+
+    private final List<String> _delims;
+    private final List<String> _tokens;
+
+    public QueryPartCollectionProcessor() {
+        _tokens = new ArrayList<String>();
+        _delims = new ArrayList<String>();
+    }
+
+    @Override
+    public void parse(String delim, String token) {
+        _delims.add(delim);
+        _tokens.add(token);
+    }
+    
+    public List<String> getDelims() {
+        return _delims;
+    }
+
+    public List<String> getTokens() {
+        return _tokens;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/parser/QueryPartParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/QueryPartParser.java b/core/src/main/java/org/apache/metamodel/query/parser/QueryPartParser.java
new file mode 100644
index 0000000..15050ea
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/parser/QueryPartParser.java
@@ -0,0 +1,126 @@
+/**
+ * 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.query.parser;
+
+/**
+ * Parser of query parts. This parser is aware of parenthesis symbols '(' and
+ * ')' and only yields tokens that have balanced parentheses. Delimitors are
+ * configurable.
+ */
+public final class QueryPartParser {
+
+    private final QueryPartProcessor _processor;
+    private final String _clause;
+    private final String[] _ItemDelims;
+
+    public QueryPartParser(QueryPartProcessor processor, String clause, String... itemDelims) {
+        if (clause == null) {
+            throw new IllegalArgumentException("Clause cannot be null");
+        }
+        if (itemDelims == null || itemDelims.length == 0) {
+            throw new IllegalArgumentException("Item delimitors cannot be null or empty");
+        }
+        _processor = processor;
+        _clause = clause;
+        _ItemDelims = itemDelims;
+    }
+
+    public void parse() {
+        if (_clause.isEmpty()) {
+            return;
+        }
+
+        int parenthesisCount = 0;
+        int offset = 0;
+        boolean singleOuterParenthesis = _clause.charAt(0) == '(' && _clause.charAt(_clause.length() - 1) == ')';
+
+        String previousDelim = null;
+        DelimOccurrence nextDelimOccurrence = getNextDelim(0);
+        if (nextDelimOccurrence != null) {
+            for (int i = 0; i < _clause.length(); i++) {
+                char c = _clause.charAt(i);
+                if (c == '(') {
+                    parenthesisCount++;
+                } else if (c == ')') {
+                    parenthesisCount--;
+                    if (singleOuterParenthesis && parenthesisCount == 0 && i != _clause.length() - 1) {
+                        singleOuterParenthesis = false;
+                    }
+                }
+                if (i == nextDelimOccurrence.index) {
+                    if (parenthesisCount == 0) {
+                        // token bounds has been identified
+                        String itemToken = _clause.substring(offset, i);
+                        parseItem(previousDelim, itemToken);
+                        offset = i + nextDelimOccurrence.delim.length();
+                        previousDelim = nextDelimOccurrence.delim;
+                    }
+                    nextDelimOccurrence = getNextDelim(nextDelimOccurrence.index + 1);
+                    if (nextDelimOccurrence == null) {
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (singleOuterParenthesis) {
+            String newClause = _clause.substring(1, _clause.length() - 1);
+            // re-run based on new clause
+            QueryPartParser newParser = new QueryPartParser(_processor, newClause, _ItemDelims);
+            newParser.parse();
+            return;
+        }
+
+        // last token will occur outside loop
+        if (offset != _clause.length()) {
+            final String token = _clause.substring(offset);
+            parseItem(previousDelim, token);
+        }
+    }
+
+    private static class DelimOccurrence {
+        public int index;
+        public String delim;
+    }
+
+    private DelimOccurrence getNextDelim(int offset) {
+        DelimOccurrence result = null;
+        for (int i = 0; i < _ItemDelims.length; i++) {
+            String delim = _ItemDelims[i];
+            int index = _clause.indexOf(delim, offset);
+            if (index != -1) {
+                if (result == null || index == Math.min(result.index, index)) {
+                    result = new DelimOccurrence();
+                    result.index = index;
+                    result.delim = delim;
+                }
+            }
+        }
+        return result;
+    }
+
+    private void parseItem(String delim, String token) {
+        if (token != null) {
+            token = token.trim();
+            if (!token.isEmpty()) {
+                _processor.parse(delim, token);
+            }
+        }
+    }
+}