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:27 UTC

[44/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/main/java/org/apache/metamodel/query/SelectClause.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/SelectClause.java b/core/src/main/java/org/apache/metamodel/query/SelectClause.java
new file mode 100644
index 0000000..82688a5
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/SelectClause.java
@@ -0,0 +1,77 @@
+/**
+ * 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;
+
+import java.util.List;
+
+import org.eobjects.metamodel.schema.Column;
+
+/**
+ * Represents the SELECT clause of a query containing SelectItems.
+ * 
+ * @see SelectItem
+ */
+public class SelectClause extends AbstractQueryClause<SelectItem> {
+
+	private static final long serialVersionUID = -2458447191169901181L;
+	private boolean _distinct = false;
+
+	public SelectClause(Query query) {
+		super(query, AbstractQueryClause.PREFIX_SELECT, AbstractQueryClause.DELIM_COMMA);
+	}
+
+	public SelectItem getSelectItem(Column column) {
+		if (column != null) {
+			for (SelectItem item : getItems()) {
+				if (column.equals(item.getColumn())) {
+					return item;
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public String toSql(boolean includeSchemaInColumnPaths) {
+		if (getItems().size() == 0) {
+			return "";
+		}
+
+		final String sql = super.toSql(includeSchemaInColumnPaths);
+        StringBuilder sb = new StringBuilder(sql);
+		if (_distinct) {
+			sb.insert(AbstractQueryClause.PREFIX_SELECT.length(), "DISTINCT ");
+		}
+		return sb.toString();
+	}
+
+	public boolean isDistinct() {
+		return _distinct;
+	}
+
+	public void setDistinct(boolean distinct) {
+		_distinct = distinct;
+	}
+
+	@Override
+	protected void decorateIdentity(List<Object> identifiers) {
+		super.decorateIdentity(identifiers);
+		identifiers.add(_distinct);
+	}
+}
\ 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/SelectItem.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/SelectItem.java b/core/src/main/java/org/apache/metamodel/query/SelectItem.java
new file mode 100644
index 0000000..a9b1707
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/SelectItem.java
@@ -0,0 +1,517 @@
+/**
+ * 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;
+
+import java.util.List;
+
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.ColumnType;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.util.BaseObject;
+import org.eobjects.metamodel.util.EqualsBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents a SELECT item. SelectItems can take different forms:
+ * <ul>
+ * <li>column SELECTs (selects a column from a table)</li>
+ * <li>column function SELECTs (aggregates the values of a column)</li>
+ * <li>expression SELECTs (retrieves data based on an expression (only supported
+ * for JDBC datastores)</li>
+ * <li>expression function SELECTs (retrieves databased on a function and an
+ * expression, only COUNT(*) is supported for non-JDBC datastores))</li>
+ * <li>SELECTs from subqueries (works just like column selects, but in stead of
+ * pointing to a column, it retrieves data from the select item of a subquery)</li>
+ * </ul>
+ * 
+ * @see SelectClause
+ */
+public class SelectItem extends BaseObject implements QueryItem, Cloneable {
+
+    private static final long serialVersionUID = 317475105509663973L;
+    private static final Logger logger = LoggerFactory.getLogger(SelectItem.class);
+
+    // immutable fields (essense)
+    private final Column _column;
+    private final FunctionType _function;
+    private final String _expression;
+    private final SelectItem _subQuerySelectItem;
+    private final FromItem _fromItem;
+
+    // mutable fields (tweaking)
+    private boolean _functionApproximationAllowed;
+    private Query _query;
+    private String _alias;
+
+    /**
+     * All-arguments constructor
+     * 
+     * @param column
+     * @param fromItem
+     * @param function
+     * @param expression
+     * @param subQuerySelectItem
+     * @param alias
+     * @param functionApproximationAllowed
+     */
+    private SelectItem(Column column, FromItem fromItem, FunctionType function, String expression,
+            SelectItem subQuerySelectItem, String alias, boolean functionApproximationAllowed) {
+        super();
+        _column = column;
+        _fromItem = fromItem;
+        _function = function;
+        _expression = expression;
+        _subQuerySelectItem = subQuerySelectItem;
+        _alias = alias;
+        _functionApproximationAllowed = functionApproximationAllowed;
+    }
+
+    /**
+     * Generates a COUNT(*) select item
+     */
+    public static SelectItem getCountAllItem() {
+        return new SelectItem(FunctionType.COUNT, "*", null);
+    }
+
+    public static boolean isCountAllItem(SelectItem item) {
+        if (item != null && item.getFunction() == FunctionType.COUNT && item.getExpression() == "*") {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Creates a simple SelectItem that selects from a column
+     * 
+     * @param column
+     */
+    public SelectItem(Column column) {
+        this(null, column);
+    }
+
+    /**
+     * Creates a SelectItem that uses a function on a column, for example
+     * SUM(price) or MAX(age)
+     * 
+     * @param function
+     * @param column
+     */
+    public SelectItem(FunctionType function, Column column) {
+        this(function, column, null);
+    }
+
+    /**
+     * Creates a SelectItem that references a column from a particular
+     * {@link FromItem}, for example a.price or p.age
+     * 
+     * @param column
+     * @param fromItem
+     */
+    public SelectItem(Column column, FromItem fromItem) {
+        this(null, column, fromItem);
+        if (fromItem != null) {
+            Table fromItemTable = fromItem.getTable();
+            if (fromItemTable != null) {
+                Table columnTable = column.getTable();
+                if (columnTable != null && !columnTable.equals(fromItemTable)) {
+                    throw new IllegalArgumentException("Column's table '" + columnTable.getName()
+                            + "' is not equal to referenced table: " + fromItemTable);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a SelectItem that uses a function on a column from a particular
+     * {@link FromItem}, for example SUM(a.price) or MAX(p.age)
+     * 
+     * @param function
+     * @param column
+     * @param fromItem
+     */
+    public SelectItem(FunctionType function, Column column, FromItem fromItem) {
+        this(column, fromItem, function, null, null, null, false);
+        if (column == null) {
+            throw new IllegalArgumentException("column=null");
+        }
+    }
+
+    /**
+     * Creates a SelectItem based on an expression. All expression-based
+     * SelectItems must have aliases.
+     * 
+     * @param expression
+     * @param alias
+     */
+    public SelectItem(String expression, String alias) {
+        this(null, expression, alias);
+    }
+
+    /**
+     * Creates a SelectItem based on a function and an expression. All
+     * expression-based SelectItems must have aliases.
+     * 
+     * @param function
+     * @param expression
+     * @param alias
+     */
+    public SelectItem(FunctionType function, String expression, String alias) {
+        this(null, null, function, expression, null, alias, false);
+        if (expression == null) {
+            throw new IllegalArgumentException("expression=null");
+        }
+    }
+
+    /**
+     * Creates a SelectItem that references another select item in a subquery
+     * 
+     * @param subQuerySelectItem
+     * @param subQueryFromItem
+     *            the FromItem that holds the sub-query
+     */
+    public SelectItem(SelectItem subQuerySelectItem, FromItem subQueryFromItem) {
+        this(null, subQueryFromItem, null, null, subQuerySelectItem, null, false);
+        if (subQueryFromItem.getSubQuery() == null) {
+            throw new IllegalArgumentException("Only sub-query based FromItems allowed.");
+        }
+        if (subQuerySelectItem.getQuery() != null
+                && !subQuerySelectItem.getQuery().equals(subQueryFromItem.getSubQuery())) {
+            throw new IllegalArgumentException("The SelectItem must exist in the sub-query");
+        }
+    }
+
+    public String getAlias() {
+        return _alias;
+    }
+
+    public SelectItem setAlias(String alias) {
+        _alias = alias;
+        return this;
+    }
+
+    public FunctionType getFunction() {
+        return _function;
+    }
+
+    /**
+     * @return if this is a function based SelectItem where function calculation
+     *         is allowed to be approximated (if the datastore type has an
+     *         approximate calculation method). Approximated function results
+     *         are as the name implies not exact, but might be valuable as an
+     *         optimization in some cases.
+     */
+    public boolean isFunctionApproximationAllowed() {
+        return _functionApproximationAllowed;
+    }
+
+    public void setFunctionApproximationAllowed(boolean functionApproximationAllowed) {
+        _functionApproximationAllowed = functionApproximationAllowed;
+    }
+
+    public Column getColumn() {
+        return _column;
+    }
+
+    /**
+     * Tries to infer the {@link ColumnType} of this {@link SelectItem}. For
+     * expression based select items, this is not possible, and the method will
+     * return null.
+     * 
+     * @return
+     */
+    public ColumnType getExpectedColumnType() {
+        if (_subQuerySelectItem != null) {
+            return _subQuerySelectItem.getExpectedColumnType();
+        }
+        if (_function != null) {
+            if (_column != null) {
+                return _function.getExpectedColumnType(_column.getType());
+            } else {
+                return _function.getExpectedColumnType(null);
+            }
+        }
+        if (_column != null) {
+            return _column.getType();
+        }
+        return null;
+    }
+
+    public String getExpression() {
+        return _expression;
+    }
+
+    public SelectItem setQuery(Query query) {
+        _query = query;
+        return this;
+    }
+
+    public Query getQuery() {
+        return _query;
+    }
+
+    public SelectItem getSubQuerySelectItem() {
+        return _subQuerySelectItem;
+    }
+
+    /**
+     * @deprecated use {@link #getFromItem()} instead
+     */
+    @Deprecated
+    public FromItem getSubQueryFromItem() {
+        return _fromItem;
+    }
+
+    public FromItem getFromItem() {
+        return _fromItem;
+    }
+
+    /**
+     * @return the name that this SelectItem can be referenced with, if
+     *         referenced from a super-query. This will usually be the alias,
+     *         but if there is no alias, then the column name will be used.
+     */
+    public String getSuperQueryAlias() {
+        return getSuperQueryAlias(true);
+    }
+
+    /**
+     * @return the name that this SelectItem can be referenced with, if
+     *         referenced from a super-query. This will usually be the alias,
+     *         but if there is no alias, then the column name will be used.
+     * 
+     * @param includeQuotes
+     *            indicates whether or not the output should include quotes, if
+     *            the select item's column has quotes associated (typically
+     *            true, but false if used for presentation)
+     */
+    public String getSuperQueryAlias(boolean includeQuotes) {
+        if (_alias != null) {
+            return _alias;
+        } else if (_column != null) {
+            final StringBuilder sb = new StringBuilder();
+            if (_function != null) {
+                sb.append(_function.toString());
+                sb.append('(');
+            }
+            if (includeQuotes) {
+                sb.append(_column.getQuotedName());
+            } else {
+                sb.append(_column.getName());
+            }
+            if (_function != null) {
+                sb.append(')');
+            }
+            return sb.toString();
+        } else {
+            logger.debug("Could not resolve a reasonable super-query alias for SelectItem: {}", toSql());
+            return toStringNoAlias().toString();
+        }
+    }
+
+    public String getSameQueryAlias() {
+        return getSameQueryAlias(false);
+    }
+
+    /**
+     * @return an alias that can be used in WHERE, GROUP BY and ORDER BY clauses
+     *         in the same query
+     */
+    public String getSameQueryAlias(boolean includeSchemaInColumnPath) {
+        if (_column != null) {
+            StringBuilder sb = new StringBuilder();
+            String columnPrefix = getToStringColumnPrefix(includeSchemaInColumnPath);
+            sb.append(columnPrefix);
+            sb.append(_column.getQuotedName());
+            if (_function != null) {
+                sb.insert(0, _function + "(");
+                sb.append(")");
+            }
+            return sb.toString();
+        }
+        String alias = getAlias();
+        if (alias == null) {
+            alias = toStringNoAlias(includeSchemaInColumnPath).toString();
+            logger.debug("Could not resolve a reasonable same-query alias for SelectItem: {}", toSql());
+        }
+        return alias;
+    }
+
+    @Override
+    public String toSql() {
+        return toSql(false);
+    }
+
+    @Override
+    public String toSql(boolean includeSchemaInColumnPath) {
+        StringBuilder sb = toStringNoAlias(includeSchemaInColumnPath);
+        if (_alias != null) {
+            sb.append(" AS ");
+            sb.append(_alias);
+        }
+        return sb.toString();
+    }
+
+    public StringBuilder toStringNoAlias() {
+        return toStringNoAlias(false);
+    }
+
+    public StringBuilder toStringNoAlias(boolean includeSchemaInColumnPath) {
+        StringBuilder sb = new StringBuilder();
+        if (_column != null) {
+            sb.append(getToStringColumnPrefix(includeSchemaInColumnPath));
+            sb.append(_column.getQuotedName());
+        }
+        if (_expression != null) {
+            sb.append(_expression);
+        }
+        if (_fromItem != null && _subQuerySelectItem != null) {
+            if (_fromItem.getAlias() != null) {
+                sb.append(_fromItem.getAlias() + '.');
+            }
+            sb.append(_subQuerySelectItem.getSuperQueryAlias());
+        }
+        if (_function != null) {
+            sb.insert(0, _function + "(");
+            sb.append(")");
+        }
+        return sb;
+    }
+
+    private String getToStringColumnPrefix(boolean includeSchemaInColumnPath) {
+        StringBuilder sb = new StringBuilder();
+        if (_fromItem != null && _fromItem.getAlias() != null) {
+            sb.append(_fromItem.getAlias());
+            sb.append('.');
+        } else {
+            final Table table = _column.getTable();
+            String tableLabel;
+            if (_query == null) {
+                tableLabel = null;
+            } else {
+                tableLabel = _query.getFromClause().getAlias(table);
+            }
+            if (table != null) {
+                if (tableLabel == null) {
+                    tableLabel = table.getQuotedName();
+                    if (includeSchemaInColumnPath) {
+                        Schema schema = table.getSchema();
+                        if (schema != null) {
+                            tableLabel = schema.getQuotedName() + "." + tableLabel;
+                        }
+                    }
+                }
+                sb.append(tableLabel);
+                sb.append('.');
+            }
+        }
+        return sb.toString();
+    }
+
+    public boolean equalsIgnoreAlias(SelectItem that) {
+        return equalsIgnoreAlias(that, false);
+    }
+
+    public boolean equalsIgnoreAlias(SelectItem that, boolean exactColumnCompare) {
+        if (that == null) {
+            return false;
+        }
+        if (that == this) {
+            return true;
+        }
+
+        EqualsBuilder eb = new EqualsBuilder();
+        if (exactColumnCompare) {
+            eb.append(this._column == that._column);
+            eb.append(this._fromItem, that._fromItem);
+        } else {
+            eb.append(this._column, that._column);
+        }
+        eb.append(this._function, that._function);
+        eb.append(this._functionApproximationAllowed, that._functionApproximationAllowed);
+        eb.append(this._expression, that._expression);
+        if (_subQuerySelectItem != null) {
+            eb.append(_subQuerySelectItem.equalsIgnoreAlias(that._subQuerySelectItem));
+        } else {
+            if (that._subQuerySelectItem != null) {
+                eb.append(false);
+            }
+        }
+        return eb.isEquals();
+    }
+
+    @Override
+    protected void decorateIdentity(List<Object> identifiers) {
+        identifiers.add(_expression);
+        identifiers.add(_alias);
+        identifiers.add(_column);
+        identifiers.add(_function);
+        identifiers.add(_functionApproximationAllowed);
+        identifiers.add(_fromItem);
+        identifiers.add(_subQuerySelectItem);
+    }
+
+    @Override
+    protected SelectItem clone() {
+        final SelectItem subQuerySelectItem = (_subQuerySelectItem == null ? null : _subQuerySelectItem.clone());
+        final FromItem fromItem = (_fromItem == null ? null : _fromItem.clone());
+        final SelectItem s = new SelectItem(_column, fromItem, _function, _expression, subQuerySelectItem, _alias,
+                _functionApproximationAllowed);
+        return s;
+    }
+
+    /**
+     * Creates a copy of the {@link SelectItem}, with a different
+     * {@link FunctionType}.
+     * 
+     * @param function
+     * @return
+     */
+    public SelectItem replaceFunction(FunctionType function) {
+        return new SelectItem(_column, _fromItem, function, _expression, _subQuerySelectItem, _alias,
+                _functionApproximationAllowed);
+    }
+
+    /**
+     * Investigates whether or not this SelectItem references a particular
+     * column. This will search for direct references and indirect references
+     * via subqueries.
+     * 
+     * @param column
+     * @return a boolean that is true if the specified column is referenced by
+     *         this SelectItem and false otherwise.
+     */
+    public boolean isReferenced(Column column) {
+        if (column != null) {
+            if (column.equals(_column)) {
+                return true;
+            }
+            if (_subQuerySelectItem != null) {
+                return _subQuerySelectItem.isReferenced(column);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toSql();
+    }
+}
\ 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/SumAggregateBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/SumAggregateBuilder.java b/core/src/main/java/org/apache/metamodel/query/SumAggregateBuilder.java
new file mode 100644
index 0000000..2cf8811
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/SumAggregateBuilder.java
@@ -0,0 +1,45 @@
+/**
+ * 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;
+
+import org.eobjects.metamodel.util.AggregateBuilder;
+import org.eobjects.metamodel.util.NumberComparator;
+
+final class SumAggregateBuilder implements AggregateBuilder<Double> {
+
+	private double sum;
+
+	@Override
+	public void add(Object o) {
+		if (o == null) {
+			return;
+		}
+		Number number = NumberComparator.toNumber(o);
+		if (number == null) {
+			throw new IllegalArgumentException("Could not convert to number: " + o);
+		}
+		sum += number.doubleValue();
+	}
+
+	@Override
+	public Double getAggregate() {
+		return sum;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/AbstractFilterBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/AbstractFilterBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/AbstractFilterBuilder.java
new file mode 100644
index 0000000..2d3bd25
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/AbstractFilterBuilder.java
@@ -0,0 +1,459 @@
+/**
+ * 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.Collection;
+import java.util.Date;
+
+import org.eobjects.metamodel.query.FilterItem;
+import org.eobjects.metamodel.query.OperatorType;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+/**
+ * Abstract implementation of {@link FilterBuilder} interface. All built filters
+ * are channeled to the {@link #applyFilter(FilterItem)} method which needs to
+ * be implemented by concrete implementations.
+ */
+public abstract class AbstractFilterBuilder<B> implements FilterBuilder<B> {
+
+    private final SelectItem _selectItem;
+
+    public AbstractFilterBuilder(SelectItem selectItem) {
+        this._selectItem = selectItem;
+    }
+
+    protected abstract B applyFilter(FilterItem filter);
+
+    /**
+     * Provides a way to
+     * 
+     * @param queryParameter
+     * @return
+     */
+    public B applyFilter(OperatorType operator, Object operand) {
+        return applyFilter(new FilterItem(_selectItem, operator, operand));
+    }
+
+    @Override
+    public B in(Collection<?> values) {
+        return applyFilter(new FilterItem(_selectItem, OperatorType.IN, values));
+    }
+
+    @Override
+    public B in(Number... numbers) {
+        return applyFilter(new FilterItem(_selectItem, OperatorType.IN, numbers));
+    }
+
+    @Override
+    public B in(String... strings) {
+        return applyFilter(new FilterItem(_selectItem, OperatorType.IN, strings));
+    }
+
+    @Override
+    public B isNull() {
+        return applyFilter(new FilterItem(_selectItem, OperatorType.EQUALS_TO, null));
+    }
+
+    @Override
+    public B isNotNull() {
+        return applyFilter(new FilterItem(_selectItem, OperatorType.DIFFERENT_FROM, null));
+    }
+
+    @Override
+    public B isEquals(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.EQUALS_TO, new SelectItem(column)));
+    }
+
+    @Override
+    public B isEquals(Date date) {
+        if (date == null) {
+            throw new IllegalArgumentException("date cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.EQUALS_TO, date));
+    }
+
+    @Override
+    public B isEquals(Number number) {
+        if (number == null) {
+            throw new IllegalArgumentException("number cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.EQUALS_TO, number));
+    }
+
+    @Override
+    public B isEquals(String string) {
+        if (string == null) {
+            throw new IllegalArgumentException("string cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.EQUALS_TO, string));
+    }
+
+    @Override
+    public B isEquals(Boolean bool) {
+        if (bool == null) {
+            throw new IllegalArgumentException("bool cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.EQUALS_TO, bool));
+    }
+
+    @Override
+    public B isEquals(Object obj) {
+        if (obj == null) {
+            return isNull();
+        }
+        if (obj instanceof Boolean) {
+            return isEquals((Boolean) obj);
+        }
+        if (obj instanceof Number) {
+            return isEquals((Number) obj);
+        }
+        if (obj instanceof Date) {
+            return isEquals((Date) obj);
+        }
+        if (obj instanceof String) {
+            return isEquals((String) obj);
+        }
+        throw new UnsupportedOperationException("Argument must be a Boolean, Number, Date or String. Found: " + obj);
+    }
+
+    @Override
+    public B differentFrom(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.DIFFERENT_FROM, new SelectItem(column)));
+    }
+
+    @Override
+    public B differentFrom(Date date) {
+        if (date == null) {
+            throw new IllegalArgumentException("date cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.DIFFERENT_FROM, date));
+    }
+
+    @Override
+    public B differentFrom(Number number) {
+        if (number == null) {
+            throw new IllegalArgumentException("number cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.DIFFERENT_FROM, number));
+    }
+
+    @Override
+    public B differentFrom(String string) {
+        if (string == null) {
+            throw new IllegalArgumentException("string cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.DIFFERENT_FROM, string));
+    }
+
+    @Override
+    public B differentFrom(Boolean bool) {
+        if (bool == null) {
+            throw new IllegalArgumentException("bool cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.DIFFERENT_FROM, bool));
+    }
+
+    @Override
+    public B differentFrom(Object obj) {
+        if (obj == null) {
+            return isNotNull();
+        }
+        if (obj instanceof Boolean) {
+            return differentFrom((Boolean) obj);
+        }
+        if (obj instanceof Number) {
+            return differentFrom((Number) obj);
+        }
+        if (obj instanceof Date) {
+            return differentFrom((Date) obj);
+        }
+        if (obj instanceof String) {
+            return differentFrom((String) obj);
+        }
+        throw new UnsupportedOperationException("Argument must be a Boolean, Number, Date or String. Found: " + obj);
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(Column arg) {
+        return greaterThan(arg);
+    }
+
+    @Override
+    public B greaterThan(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.GREATER_THAN, new SelectItem(column)));
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(Date arg) {
+        return greaterThan(arg);
+    }
+
+    @Override
+    public B greaterThan(Date date) {
+        if (date == null) {
+            throw new IllegalArgumentException("date cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.GREATER_THAN, date));
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(Number arg) {
+        return greaterThan(arg);
+    }
+
+    @Override
+    public B greaterThan(Number number) {
+        if (number == null) {
+            throw new IllegalArgumentException("number cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.GREATER_THAN, number));
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(String arg) {
+        return greaterThan(arg);
+    }
+
+    @Override
+    public B greaterThan(String string) {
+        if (string == null) {
+            throw new IllegalArgumentException("string cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.GREATER_THAN, string));
+    }
+
+    @Override
+    public B lessThan(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.LESS_THAN, new SelectItem(column)));
+    }
+
+    @Override
+    public B lessThan(Date date) {
+        if (date == null) {
+            throw new IllegalArgumentException("date cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.LESS_THAN, date));
+    }
+
+    @Override
+    public B lessThan(Number number) {
+        if (number == null) {
+            throw new IllegalArgumentException("number cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.LESS_THAN, number));
+    }
+
+    @Override
+    public B lessThan(String string) {
+        if (string == null) {
+            throw new IllegalArgumentException("string cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.LESS_THAN, string));
+    }
+    
+    @Override
+    public B lessThan(Object obj) {
+        if (obj instanceof Number) {
+            return lessThan((Number) obj);
+        }
+        if (obj instanceof Date) {
+            return lessThan((Date) obj);
+        }
+        if (obj instanceof String) {
+            return lessThan((String) obj);
+        }
+        throw new UnsupportedOperationException("Argument must be a Number, Date or String. Found: " + obj);
+    }
+    
+    @Override
+    public B greaterThan(Object obj) {
+        if (obj instanceof Number) {
+            return greaterThan((Number) obj);
+        }
+        if (obj instanceof Date) {
+            return greaterThan((Date) obj);
+        }
+        if (obj instanceof String) {
+            return greaterThan((String) obj);
+        }
+        throw new UnsupportedOperationException("Argument must be a Number, Date or String. Found: " + obj);
+    }
+
+    @Override
+    public B like(String string) {
+        if (string == null) {
+            throw new IllegalArgumentException("string cannot be null");
+        }
+        return applyFilter(new FilterItem(_selectItem, OperatorType.LIKE, string));
+    }
+
+    @Override
+    public B gt(Column column) {
+        return greaterThan(column);
+    }
+
+    @Override
+    public B gt(Date date) {
+        return greaterThan(date);
+    }
+
+    @Override
+    public B gt(Number number) {
+        return greaterThan(number);
+    }
+
+    @Override
+    public B gt(String string) {
+        return greaterThan(string);
+    }
+
+    @Override
+    public B lt(Column column) {
+        return lessThan(column);
+    }
+
+    public B lt(Date date) {
+        return lessThan(date);
+    };
+
+    public B lt(Number number) {
+        return lessThan(number);
+    };
+
+    public B lt(String string) {
+        return lessThan(string);
+    };
+
+    @Override
+    public B eq(Boolean bool) {
+        return isEquals(bool);
+    }
+
+    @Override
+    public B eq(Column column) {
+        return isEquals(column);
+    }
+
+    @Override
+    public B eq(Date date) {
+        return isEquals(date);
+    }
+
+    @Override
+    public B eq(Number number) {
+        return isEquals(number);
+    }
+
+    @Override
+    public B eq(String string) {
+        return isEquals(string);
+    }
+
+    @Override
+    public B eq(Object obj) {
+        return isEquals(obj);
+    }
+
+    @Override
+    public B ne(Boolean bool) {
+        return differentFrom(bool);
+    }
+
+    @Override
+    public B ne(Column column) {
+        return differentFrom(column);
+    }
+
+    @Override
+    public B ne(Date date) {
+        return differentFrom(date);
+    }
+
+    @Override
+    public B ne(Number number) {
+        return differentFrom(number);
+    }
+
+    @Override
+    public B ne(String string) {
+        return differentFrom(string);
+    }
+
+    @Override
+    public B ne(Object obj) {
+        return differentFrom(obj);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Boolean bool) {
+        return isEquals(bool);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Column column) {
+        return isEquals(column);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Date date) {
+        return isEquals(date);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Number number) {
+        return isEquals(number);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(String string) {
+        return isEquals(string);
+    }
+    
+    @Override
+    public B lt(Object obj) {
+        return lessThan(obj);
+    }
+    
+    @Override
+    public B gt(Object obj) {
+        return greaterThan(obj);
+    }
+}
\ 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/AbstractQueryFilterBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/AbstractQueryFilterBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/AbstractQueryFilterBuilder.java
new file mode 100644
index 0000000..a015292
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/AbstractQueryFilterBuilder.java
@@ -0,0 +1,344 @@
+/**
+ * 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.Collection;
+import java.util.Date;
+
+import org.eobjects.metamodel.query.FilterItem;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+abstract class AbstractQueryFilterBuilder<B> extends GroupedQueryBuilderCallback implements FilterBuilder<B> {
+
+    protected final AbstractFilterBuilder<B> _filterBuilder;
+
+    public AbstractQueryFilterBuilder(SelectItem selectItem, GroupedQueryBuilder queryBuilder) {
+        super(queryBuilder);
+        _filterBuilder = new AbstractFilterBuilder<B>(selectItem) {
+            @Override
+            protected B applyFilter(FilterItem filter) {
+                return AbstractQueryFilterBuilder.this.applyFilter(filter);
+            }
+        };
+    }
+
+    protected abstract B applyFilter(FilterItem filter);
+
+    @Override
+    public B in(Collection<?> values) {
+        return _filterBuilder.in(values);
+    }
+
+    @Override
+    public B in(Number... numbers) {
+        return _filterBuilder.in(numbers);
+    }
+
+    @Override
+    public B in(String... strings) {
+        return _filterBuilder.in(strings);
+    }
+
+    @Override
+    public B isNull() {
+        return _filterBuilder.isNull();
+    }
+
+    @Override
+    public B isNotNull() {
+        return _filterBuilder.isNotNull();
+    }
+
+    @Override
+    public B isEquals(Column column) {
+        return _filterBuilder.isEquals(column);
+    }
+
+    @Override
+    public B isEquals(Date date) {
+        return _filterBuilder.isEquals(date);
+    }
+
+    @Override
+    public B isEquals(Number number) {
+        return _filterBuilder.isEquals(number);
+    }
+
+    @Override
+    public B isEquals(String string) {
+        return _filterBuilder.isEquals(string);
+    }
+
+    @Override
+    public B isEquals(Boolean bool) {
+        return _filterBuilder.isEquals(bool);
+    }
+    
+    @Override
+    public B isEquals(Object obj) {
+        return _filterBuilder.isEquals(obj);
+    }
+
+    @Override
+    public B differentFrom(Column column) {
+        return _filterBuilder.differentFrom(column);
+    }
+
+    @Override
+    public B differentFrom(Date date) {
+        return _filterBuilder.differentFrom(date);
+    }
+
+    @Override
+    public B differentFrom(Number number) {
+        return _filterBuilder.differentFrom(number);
+    }
+
+    @Override
+    public B differentFrom(String string) {
+        return _filterBuilder.differentFrom(string);
+    }
+
+    @Override
+    public B differentFrom(Boolean bool) {
+        return _filterBuilder.differentFrom(bool);
+    }
+
+    @Override
+    public B differentFrom(Object obj) {
+        return _filterBuilder.differentFrom(obj);
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(Column arg) {
+        return _filterBuilder.higherThan(arg);
+    }
+
+    public B greaterThan(Column column) {
+        return _filterBuilder.greaterThan(column);
+    }
+    
+    @Override
+    public B greaterThan(Object obj) {
+        return _filterBuilder.greaterThan(obj);
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(Date arg) {
+        return _filterBuilder.higherThan(arg);
+    }
+
+    @Override
+    public B greaterThan(Date date) {
+        return _filterBuilder.greaterThan(date);
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(Number arg) {
+        return _filterBuilder.higherThan(arg);
+    }
+
+    @Override
+    public B greaterThan(Number number) {
+        return _filterBuilder.greaterThan(number);
+    }
+
+    @Deprecated
+    @Override
+    public B higherThan(String arg) {
+        return _filterBuilder.higherThan(arg);
+    }
+
+    @Override
+    public B greaterThan(String string) {
+        return _filterBuilder.greaterThan(string);
+    }
+
+    @Override
+    public B lessThan(Column column) {
+        return _filterBuilder.lessThan(column);
+    }
+
+    @Override
+    public B lessThan(Date date) {
+        return _filterBuilder.lessThan(date);
+    }
+
+    @Override
+    public B lessThan(Number number) {
+        return _filterBuilder.lessThan(number);
+    }
+
+    @Override
+    public B lessThan(String string) {
+        return _filterBuilder.lessThan(string);
+    }
+    
+    @Override
+    public B lessThan(Object obj) {
+        return _filterBuilder.lessThan(obj);
+    }
+
+    @Override
+    public B like(String string) {
+        return _filterBuilder.like(string);
+    }
+
+    @Override
+    public B gt(Column column) {
+        return greaterThan(column);
+    }
+
+    @Override
+    public B gt(Date date) {
+        return greaterThan(date);
+    }
+
+    @Override
+    public B gt(Number number) {
+        return greaterThan(number);
+    }
+
+    @Override
+    public B gt(String string) {
+        return greaterThan(string);
+    }
+
+    @Override
+    public B lt(Column column) {
+        return lessThan(column);
+    }
+
+    public B lt(Date date) {
+        return lessThan(date);
+    };
+
+    public B lt(Number number) {
+        return lessThan(number);
+    };
+
+    public B lt(String string) {
+        return lessThan(string);
+    };
+
+    @Override
+    public B eq(Boolean bool) {
+        return isEquals(bool);
+    }
+
+    @Override
+    public B eq(Column column) {
+        return isEquals(column);
+    }
+
+    @Override
+    public B eq(Date date) {
+        return isEquals(date);
+    }
+
+    @Override
+    public B eq(Number number) {
+        return isEquals(number);
+    }
+
+    @Override
+    public B eq(String string) {
+        return isEquals(string);
+    }
+
+    @Override
+    public B eq(Object obj) {
+        return isEquals(obj);
+    }
+
+    @Override
+    public B ne(Boolean bool) {
+        return differentFrom(bool);
+    }
+
+    @Override
+    public B ne(Column column) {
+        return differentFrom(column);
+    }
+
+    @Override
+    public B ne(Date date) {
+        return differentFrom(date);
+    }
+
+    @Override
+    public B ne(Number number) {
+        return differentFrom(number);
+    }
+
+    @Override
+    public B ne(String string) {
+        return differentFrom(string);
+    }
+
+    @Override
+    public B ne(Object obj) {
+        return differentFrom(obj);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Boolean bool) {
+        return isEquals(bool);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Column column) {
+        return isEquals(column);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Date date) {
+        return isEquals(date);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(Number number) {
+        return isEquals(number);
+    }
+
+    @Override
+    @Deprecated
+    public B equals(String string) {
+        return isEquals(string);
+    }
+    
+    @Override
+    public B lt(Object obj) {
+        return lessThan(obj);
+    }
+    
+    @Override
+    public B gt(Object obj) {
+        return greaterThan(obj);
+    }
+    
+}
\ 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/ColumnSelectBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/ColumnSelectBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/ColumnSelectBuilder.java
new file mode 100644
index 0000000..00208cf
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/ColumnSelectBuilder.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+public interface ColumnSelectBuilder<B extends SatisfiedQueryBuilder<?>>
+		extends SatisfiedSelectBuilder<B> {
+
+	public B as(String alias);
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/ColumnSelectBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/ColumnSelectBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/ColumnSelectBuilderImpl.java
new file mode 100644
index 0000000..161a36f
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/ColumnSelectBuilderImpl.java
@@ -0,0 +1,54 @@
+/**
+ * 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.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+final class ColumnSelectBuilderImpl extends SatisfiedSelectBuilderImpl
+		implements ColumnSelectBuilder<GroupedQueryBuilder> {
+
+	private SelectItem selectItem;
+
+	public ColumnSelectBuilderImpl(Column column, Query query,
+			GroupedQueryBuilder queryBuilder) {
+		super(queryBuilder);
+		this.selectItem = new SelectItem(column);
+
+		query.select(selectItem);
+	}
+
+	@Override
+	public GroupedQueryBuilder as(String alias) {
+		if (alias == null) {
+			throw new IllegalArgumentException("alias cannot be null");
+		}
+		selectItem.setAlias(alias);
+		return getQueryBuilder();
+	}
+
+	@Override
+	protected void decorateIdentity(List<Object> identifiers) {
+		super.decorateIdentity(identifiers);
+		identifiers.add(selectItem);
+	}
+}
\ 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/CountSelectBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/CountSelectBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/CountSelectBuilder.java
new file mode 100644
index 0000000..61dd73d
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/CountSelectBuilder.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+public interface CountSelectBuilder<B extends SatisfiedQueryBuilder<?>> extends
+		SatisfiedSelectBuilder<B> {
+
+	public B as(String alias);
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/CountSelectBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/CountSelectBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/CountSelectBuilderImpl.java
new file mode 100644
index 0000000..e2114b2
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/CountSelectBuilderImpl.java
@@ -0,0 +1,51 @@
+/**
+ * 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.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+
+final class CountSelectBuilderImpl extends SatisfiedSelectBuilderImpl implements
+		CountSelectBuilder<GroupedQueryBuilder> {
+
+	private SelectItem selectItem;
+
+	public CountSelectBuilderImpl(Query query, GroupedQueryBuilder queryBuilder) {
+		super(queryBuilder);
+		this.selectItem = SelectItem.getCountAllItem();
+		query.select(selectItem);
+	}
+
+	@Override
+	public GroupedQueryBuilder as(String alias) {
+		if (alias == null) {
+			throw new IllegalArgumentException("alias cannot be null");
+		}
+		selectItem.setAlias(alias);
+		return getQueryBuilder();
+	}
+
+	@Override
+	protected void decorateIdentity(List<Object> identifiers) {
+		super.decorateIdentity(identifiers);
+		identifiers.add(selectItem);
+	}
+}
\ 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/FilterBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/FilterBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/FilterBuilder.java
new file mode 100644
index 0000000..01a09cc
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/FilterBuilder.java
@@ -0,0 +1,355 @@
+/**
+ * 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.Collection;
+import java.util.Date;
+
+import org.eobjects.metamodel.schema.Column;
+
+/**
+ * Interface for builder callbacks that "respond" to filter condition building.
+ * 
+ * @param <B>
+ *            the builder type to return once filter has been created.
+ */
+public interface FilterBuilder<B> {
+
+    /**
+     * Not null
+     */
+    public B isNull();
+
+    /**
+     * Is not null
+     */
+    public B isNotNull();
+
+    /**
+     * In ...
+     */
+    public B in(Collection<?> values);
+
+    /**
+     * In ...
+     */
+    public B in(Number... numbers);
+
+    /**
+     * In ...
+     */
+    public B in(String... strings);
+
+    /**
+     * Like ...
+     * 
+     * (use '%' as wildcard).
+     */
+    public B like(String string);
+
+    /**
+     * Equal to ...
+     */
+    public B eq(Column column);
+
+    /**
+     * Equal to ...
+     */
+    public B eq(Date date);
+
+    /**
+     * Equal to ...
+     */
+    public B eq(Number number);
+
+    /**
+     * Equal to ...
+     */
+    public B eq(String string);
+
+    /**
+     * Equal to ...
+     */
+    public B eq(Boolean bool);
+    
+    /**
+     * Equal to ...
+     */
+    public B eq(Object obj);
+
+    /**
+     * Equal to ...
+     */
+    public B isEquals(Column column);
+
+    /**
+     * Equal to ...
+     */
+    public B isEquals(Date date);
+
+    /**
+     * Equal to ...
+     */
+    public B isEquals(Number number);
+
+    /**
+     * Equal to ...
+     */
+    public B isEquals(String string);
+
+    /**
+     * Equal to ...
+     */
+    public B isEquals(Boolean bool);
+    
+    /**
+     * Equal to ...
+     */
+    public B isEquals(Object obj);
+
+    /**
+     * Equal to ...
+     * 
+     * @deprecated use 'eq' or 'isEquals' instead.
+     */
+    @Deprecated
+    public B equals(Column column);
+
+    /**
+     * Equal to ...
+     * 
+     * @deprecated use 'eq' or 'isEquals' instead.
+     */
+    @Deprecated
+    public B equals(Date date);
+
+    /**
+     * Equal to ...
+     * 
+     * @deprecated use 'eq' or 'isEquals' instead.
+     */
+    @Deprecated
+    public B equals(Number number);
+
+    /**
+     * Equal to ...
+     * 
+     * @deprecated use 'eq' or 'isEquals' instead.
+     */
+    @Deprecated
+    public B equals(String string);
+
+    /**
+     * Equal to ...
+     * 
+     * @deprecated use 'eq' or 'isEquals' instead.
+     */
+    @Deprecated
+    public B equals(Boolean bool);
+
+    /**
+     * Not equal to ...
+     */
+    public B differentFrom(Column column);
+
+    /**
+     * Not equal to ...
+     */
+    public B differentFrom(Date date);
+
+    /**
+     * Not equal to ...
+     */
+    public B differentFrom(Number number);
+
+    /**
+     * Not equal to ...
+     */
+    public B differentFrom(String string);
+
+    /**
+     * Not equal to ...
+     */
+    public B differentFrom(Boolean bool);
+    
+    /**
+     * Not equal to ...
+     */
+    public B differentFrom(Object obj);
+
+    /**
+     * Not equal to ...
+     */
+    public B ne(Column column);
+
+    /**
+     * Not equal to ...
+     */
+    public B ne(Date date);
+
+    /**
+     * Not equal to ...
+     */
+    public B ne(Number number);
+
+    /**
+     * Not equal to ...
+     */
+    public B ne(String string);
+
+    /**
+     * Not equal to ...
+     */
+    public B ne(Boolean bool);
+    
+    /**
+     * Not equal to ...
+     */
+    public B ne(Object obj);
+
+    /**
+     * Greater than ...
+     * 
+     * @deprecated use {@link #greaterThan(Column)} instead
+     */
+    @Deprecated
+    public B higherThan(Column column);
+
+    /**
+     * Greater than ...
+     */
+    public B greaterThan(Column column);
+
+    /**
+     * Greater than ...
+     */
+    public B gt(Column column);
+    
+    /**
+     * Greater than ...
+     */
+    public B greaterThan(Object obj);
+    
+    /**
+     * Greater than ...
+     */
+    public B gt(Object obj);
+
+    /**
+     * Greater than ...
+     * 
+     * @deprecated use {@link #greaterThan(Date)} instead
+     */
+    @Deprecated
+    public B higherThan(Date date);
+
+    /**
+     * Greater than ...
+     */
+    public B greaterThan(Date date);
+
+    /**
+     * Greater than ...
+     */
+    public B gt(Date date);
+
+    /**
+     * @deprecated use {@link #greaterThan(Number)} instead
+     */
+    @Deprecated
+    public B higherThan(Number number);
+
+    /**
+     * Greater than ...
+     */
+    public B greaterThan(Number number);
+
+    /**
+     * Greater than ...
+     */
+    public B gt(Number number);
+
+    /**
+     * Greater than ...
+     * 
+     * @deprecated use {@link #greaterThan(String)} instead
+     */
+    @Deprecated
+    public B higherThan(String string);
+
+    /**
+     * Greater than ...
+     */
+    public B greaterThan(String string);
+
+    /**
+     * Greater than ...
+     */
+    public B gt(String string);
+
+    /**
+     * Less than ...
+     */
+    public B lessThan(Column column);
+
+    /**
+     * Less than ...
+     */
+    public B lt(Column column);
+
+    /**
+     * Less than ...
+     */
+    public B lessThan(Date date);
+
+    /**
+     * Less than ...
+     */
+    public B lessThan(Number number);
+
+    /**
+     * Less than ...
+     */
+    public B lessThan(String string);
+    
+    /**
+     * Less than ...
+     */
+    public B lessThan(Object obj);
+    
+    /**
+     * Less than ...
+     */
+    public B lt(Object obj);
+
+    /**
+     * Less than ...
+     */
+    public B lt(Date date);
+
+    /**
+     * Less than ...
+     */
+    public B lt(Number number);
+
+    /**
+     * Less than ...
+     */
+    public B lt(String string);
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilder.java
new file mode 100644
index 0000000..516ce5e
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilder.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+public interface FunctionSelectBuilder<B extends SatisfiedQueryBuilder<?>>
+		extends SatisfiedSelectBuilder<B> {
+
+	public B as(String alias);
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilderImpl.java
new file mode 100644
index 0000000..68e9b39
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/FunctionSelectBuilderImpl.java
@@ -0,0 +1,56 @@
+/**
+ * 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.query.FunctionType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+final class FunctionSelectBuilderImpl extends SatisfiedSelectBuilderImpl
+		implements FunctionSelectBuilder<GroupedQueryBuilder> {
+
+	private SelectItem selectItem;
+
+	public FunctionSelectBuilderImpl(FunctionType functionType, Column column,
+			Query query, GroupedQueryBuilder queryBuilder) {
+		super(queryBuilder);
+
+		this.selectItem = new SelectItem(functionType, column);
+
+		query.select(selectItem);
+	}
+
+	@Override
+	public GroupedQueryBuilder as(String alias) {
+		if (alias == null) {
+			throw new IllegalArgumentException("alias cannot be null");
+		}
+		selectItem.setAlias(alias);
+		return getQueryBuilder();
+	}
+
+	@Override
+	protected void decorateIdentity(List<Object> identifiers) {
+		super.decorateIdentity(identifiers);
+		identifiers.add(selectItem);
+	}
+}
\ 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/GroupedQueryBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilder.java
new file mode 100644
index 0000000..d798d9b
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilder.java
@@ -0,0 +1,37 @@
+/**
+ * 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;
+
+/**
+ * Represents a built query that has a GROUP BY clause.
+ * 
+ * @author Kasper Sørensen
+ * 
+ */
+public interface GroupedQueryBuilder extends
+		SatisfiedQueryBuilder<GroupedQueryBuilder> {
+
+	public HavingBuilder having(FunctionType functionType, Column column);
+
+	public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(
+			FunctionType function, 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/GroupedQueryBuilderCallback.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilderCallback.java b/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilderCallback.java
new file mode 100644
index 0000000..6db7feb
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilderCallback.java
@@ -0,0 +1,168 @@
+/**
+ * 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.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;
+import org.eobjects.metamodel.util.BaseObject;
+
+abstract class GroupedQueryBuilderCallback extends BaseObject implements GroupedQueryBuilder {
+
+    private GroupedQueryBuilder queryBuilder;
+
+    public GroupedQueryBuilderCallback(GroupedQueryBuilder queryBuilder) {
+        this.queryBuilder = queryBuilder;
+    }
+
+    protected GroupedQueryBuilder getQueryBuilder() {
+        return queryBuilder;
+    }
+    
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> firstRow(int firstRow) {
+        return getQueryBuilder().firstRow(firstRow);
+    }
+    
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> limit(int maxRows) {
+        return getQueryBuilder().limit(maxRows);
+    }
+    
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> offset(int offset) {
+        return getQueryBuilder().offset(offset);
+    }
+    
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> maxRows(int maxRows) {
+        return getQueryBuilder().maxRows(maxRows);
+    }
+
+    @Override
+    public SatisfiedSelectBuilder<GroupedQueryBuilder> select(Column... columns) {
+        return getQueryBuilder().select(columns);
+    }
+
+    @Override
+    public final Column findColumn(String columnName) throws IllegalArgumentException {
+        return getQueryBuilder().findColumn(columnName);
+    }
+
+    @Override
+    public ColumnSelectBuilder<GroupedQueryBuilder> select(Column column) {
+        return getQueryBuilder().select(column);
+    }
+
+    @Override
+    public FunctionSelectBuilder<GroupedQueryBuilder> select(FunctionType functionType, Column column) {
+        return getQueryBuilder().select(functionType, column);
+    }
+
+    @Override
+    public ColumnSelectBuilder<GroupedQueryBuilder> select(String columnName) {
+        return getQueryBuilder().select(columnName);
+    }
+
+    @Override
+    public CountSelectBuilder<GroupedQueryBuilder> selectCount() {
+        return getQueryBuilder().selectCount();
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> where(Column column) {
+        return getQueryBuilder().where(column);
+    }
+
+    @Override
+    public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(Column column) {
+        return getQueryBuilder().orderBy(column);
+    }
+
+    @Override
+    public GroupedQueryBuilder groupBy(String columnName) {
+        return getQueryBuilder().groupBy(columnName);
+    }
+
+    @Override
+    public GroupedQueryBuilder groupBy(Column column) {
+        return getQueryBuilder().groupBy(column);
+    }
+
+    @Override
+    public Query toQuery() {
+        return getQueryBuilder().toQuery();
+    }
+
+    @Override
+    public CompiledQuery compile() {
+        return getQueryBuilder().compile();
+    }
+
+    @Override
+    public HavingBuilder having(FunctionType functionType, Column column) {
+        return getQueryBuilder().having(functionType, column);
+    }
+
+    @Override
+    public GroupedQueryBuilder groupBy(Column... columns) {
+        getQueryBuilder().groupBy(columns);
+        return this;
+    }
+
+    @Override
+    protected void decorateIdentity(List<Object> identifiers) {
+        identifiers.add(queryBuilder);
+    }
+
+    @Override
+    public DataSet execute() {
+        return queryBuilder.execute();
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> where(String columnName) {
+        return getQueryBuilder().where(columnName);
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> where(FilterItem... filters) {
+        return getQueryBuilder().where(filters);
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> where(Iterable<FilterItem> filters) {
+        return getQueryBuilder().where(filters);
+    }
+
+    @Override
+    public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(String columnName) {
+        return getQueryBuilder().orderBy(columnName);
+    }
+
+    @Override
+    public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(FunctionType function, Column column) {
+        return getQueryBuilder().orderBy(function, 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/GroupedQueryBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilderImpl.java
new file mode 100644
index 0000000..bd5248c
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/GroupedQueryBuilderImpl.java
@@ -0,0 +1,332 @@
+/**
+ * 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.data.DataSet;
+import org.eobjects.metamodel.query.CompiledQuery;
+import org.eobjects.metamodel.query.FilterItem;
+import org.eobjects.metamodel.query.FromItem;
+import org.eobjects.metamodel.query.FunctionType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.util.BaseObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Main implementation of the {@link GroupedQueryBuilder} interface.
+ */
+final class GroupedQueryBuilderImpl extends BaseObject implements GroupedQueryBuilder {
+
+    private static final Logger logger = LoggerFactory.getLogger(GroupedQueryBuilderImpl.class);
+
+    private final Query _query;
+    private final DataContext _dataContext;
+
+    public GroupedQueryBuilderImpl(DataContext dataContext, Query query) {
+        if (query == null) {
+            throw new IllegalArgumentException("query cannot be null");
+        }
+        _dataContext = dataContext;
+        _query = query;
+    }
+
+    @Override
+    public ColumnSelectBuilder<GroupedQueryBuilder> select(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return new ColumnSelectBuilderImpl(column, _query, this);
+    }
+
+    @Override
+    public FunctionSelectBuilder<GroupedQueryBuilder> select(FunctionType function, Column column) {
+        if (function == null) {
+            throw new IllegalArgumentException("function cannot be null");
+        }
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return new FunctionSelectBuilderImpl(function, column, _query, this);
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> where(FilterItem... filters) {
+        _query.where(filters);
+        return this;
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> where(Iterable<FilterItem> filters) {
+        _query.where(filters);
+        return this;
+    }
+
+    @Override
+    public ColumnSelectBuilder<GroupedQueryBuilder> select(String columnName) {
+        Column column = findColumn(columnName);
+        return select(column);
+    }
+
+    @Override
+    public CountSelectBuilder<GroupedQueryBuilder> selectCount() {
+        return new CountSelectBuilderImpl(_query, this);
+    }
+
+    @Override
+    public SatisfiedSelectBuilder<GroupedQueryBuilder> select(Column... columns) {
+        if (columns == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        _query.select(columns);
+        return new SatisfiedSelectBuilderImpl(this);
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> where(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return new WhereBuilderImpl(column, _query, this);
+    }
+
+    @Override
+    public WhereBuilder<GroupedQueryBuilder> where(String columnName) {
+        Column column = findColumn(columnName);
+        return where(column);
+    }
+
+    @Override
+    public Column findColumn(final String columnName) throws IllegalArgumentException {
+        if (columnName == null) {
+            throw new IllegalArgumentException("columnName cannot be null");
+        }
+
+        final List<FromItem> fromItems = _query.getFromClause().getItems();
+        final List<SelectItem> selectItems = _query.getSelectClause().getItems();
+
+        int dotIndex = columnName.indexOf('.');
+        if (dotIndex != -1) {
+            // check aliases of from items
+            final String aliasPart = columnName.substring(0, dotIndex);
+            final String columnPart = columnName.substring(dotIndex + 1);
+
+            for (FromItem fromItem : fromItems) {
+                Column column = null;
+                column = findColumnInAliasedTable(column, fromItem, aliasPart, columnPart);
+                if (column != null) {
+                    return column;
+                }
+            }
+        }
+
+        // check columns already in select clause
+        for (SelectItem item : selectItems) {
+            Column column = item.getColumn();
+            if (column != null) {
+                if (columnName.equals(column.getName())) {
+                    return column;
+                }
+            }
+        }
+
+        for (FromItem fromItem : fromItems) {
+            Table table = fromItem.getTable();
+            if (table != null) {
+                Column column = table.getColumnByName(columnName);
+                if (column != null) {
+                    return column;
+                }
+            }
+        }
+
+        Column column = _dataContext.getColumnByQualifiedLabel(columnName);
+        if (column != null) {
+            return column;
+        }
+
+        final IllegalArgumentException exception = new IllegalArgumentException("Could not find column: " + columnName);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("findColumn('" + columnName + "') could not resolve a column", exception);
+            for (FromItem fromItem : fromItems) {
+                final Table table = fromItem.getTable();
+                if (table != null) {
+                    logger.debug("Table available in FROM item: {}. Column names: {}", table,
+                            Arrays.toString(table.getColumnNames()));
+                }
+            }
+        }
+
+        throw exception;
+    }
+
+    private Column findColumnInAliasedTable(Column column, FromItem fromItem, String aliasPart, String columnPart) {
+        if (column != null) {
+            // ensure that if the column has already been found, return it
+            return column;
+        }
+
+        Table table = fromItem.getTable();
+        if (table != null) {
+            String alias = fromItem.getAlias();
+            if (alias != null && alias.equals(aliasPart)) {
+                column = table.getColumnByName(columnPart);
+            }
+        } else {
+            FromItem leftSide = fromItem.getLeftSide();
+            column = findColumnInAliasedTable(column, leftSide, aliasPart, columnPart);
+            FromItem rightSide = fromItem.getRightSide();
+            column = findColumnInAliasedTable(column, rightSide, aliasPart, columnPart);
+            if (column != null) {
+                Query subQuery = fromItem.getSubQuery();
+                if (subQuery != null) {
+                    List<FromItem> items = subQuery.getFromClause().getItems();
+                    for (FromItem subQueryFromItem : items) {
+                        column = findColumnInAliasedTable(column, subQueryFromItem, aliasPart, columnPart);
+                    }
+                }
+            }
+        }
+
+        return column;
+    }
+
+    @Override
+    public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(String columnName) {
+        return orderBy(findColumn(columnName));
+    }
+
+    @Override
+    public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return new SatisfiedOrderByBuilderImpl(column, _query, this);
+    }
+
+    @Override
+    public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(FunctionType function, Column column) {
+        if (function == null) {
+            throw new IllegalArgumentException("function cannot be null");
+        }
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return new SatisfiedOrderByBuilderImpl(function, column, _query, this);
+    }
+
+    @Override
+    public GroupedQueryBuilder groupBy(Column column) {
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        _query.groupBy(column);
+        return this;
+    }
+
+    @Override
+    public GroupedQueryBuilder groupBy(String columnName) {
+        Column column = findColumn(columnName);
+        return groupBy(column);
+    }
+
+    @Override
+    public GroupedQueryBuilder groupBy(Column... columns) {
+        if (columns == null) {
+            throw new IllegalArgumentException("columns cannot be null");
+        }
+        _query.groupBy(columns);
+        return this;
+    }
+
+    @Override
+    public HavingBuilder having(FunctionType function, Column column) {
+        if (function == null) {
+            throw new IllegalArgumentException("function cannot be null");
+        }
+        if (column == null) {
+            throw new IllegalArgumentException("column cannot be null");
+        }
+        return new HavingBuilderImpl(function, column, _query, this);
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> limit(int maxRows) {
+        _query.setMaxRows(maxRows);
+        return this;
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> maxRows(int maxRows) {
+        _query.setMaxRows(maxRows);
+        return this;
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> firstRow(int firstRow) {
+        if (firstRow >= 0) {
+            _query.setFirstRow(firstRow);
+        } else {
+            _query.setFirstRow(null);
+        }
+        return this;
+    }
+
+    @Override
+    public SatisfiedQueryBuilder<GroupedQueryBuilder> offset(int offset) {
+        if (offset >= 0) {
+            _query.setFirstRow(offset + 1);
+        } else {
+            _query.setFirstRow(null);
+        }
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return _query.toSql();
+    }
+
+    @Override
+    public Query toQuery() {
+        return _query.clone();
+    }
+
+    @Override
+    public CompiledQuery compile() {
+        return _dataContext.compileQuery(_query);
+    }
+
+    @Override
+    public DataSet execute() {
+        return _dataContext.executeQuery(_query);
+    }
+
+    @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/HavingBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/HavingBuilder.java b/core/src/main/java/org/apache/metamodel/query/builder/HavingBuilder.java
new file mode 100644
index 0000000..1596ada
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/HavingBuilder.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;
+
+/**
+ * Builder interface for having items.
+ */
+public interface HavingBuilder extends FilterBuilder<SatisfiedHavingBuilder> {
+
+}
\ 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/HavingBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/builder/HavingBuilderImpl.java b/core/src/main/java/org/apache/metamodel/query/builder/HavingBuilderImpl.java
new file mode 100644
index 0000000..13b197d
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/query/builder/HavingBuilderImpl.java
@@ -0,0 +1,87 @@
+/**
+ * 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.FunctionType;
+import org.eobjects.metamodel.query.Query;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+
+final class HavingBuilderImpl extends
+		AbstractQueryFilterBuilder<SatisfiedHavingBuilder> implements
+		HavingBuilder, SatisfiedHavingBuilder {
+
+	private final Query _query;
+	private final List<FilterItem> _orFilters;
+	private FilterItem _parentOrFilter;
+
+	public HavingBuilderImpl(FunctionType function, Column column, Query query,
+			GroupedQueryBuilder queryBuilder) {
+		super(new SelectItem(function, column), queryBuilder);
+		_query = query;
+		_orFilters = new ArrayList<FilterItem>();
+	}
+
+	public HavingBuilderImpl(FunctionType function, Column column, Query query,
+			FilterItem parentOrFilter, List<FilterItem> orFilters,
+			GroupedQueryBuilder queryBuilder) {
+		super(new SelectItem(function, column), queryBuilder);
+		_query = query;
+		_orFilters = orFilters;
+		_parentOrFilter = parentOrFilter;
+	}
+
+	@Override
+	protected SatisfiedHavingBuilder applyFilter(FilterItem filter) {
+		if (_parentOrFilter == null) {
+			_query.having(filter);
+		} else {
+			if (_parentOrFilter.getChildItemCount() == 1) {
+				_query.getHavingClause().removeItem(_orFilters.get(0));
+				_query.getHavingClause().addItem(_parentOrFilter);
+			}
+		}
+		_orFilters.add(filter);
+		return this;
+	}
+
+	@Override
+	public HavingBuilder or(FunctionType function, Column column) {
+		if (function == null) {
+			throw new IllegalArgumentException("function cannot be null");
+		}
+		if (column == null) {
+			throw new IllegalArgumentException("column cannot be null");
+		}
+		if (_parentOrFilter == null) {
+			_parentOrFilter = new FilterItem(_orFilters);
+		}
+		return new HavingBuilderImpl(function, column, _query, _parentOrFilter,
+				_orFilters, getQueryBuilder());
+	}
+
+	@Override
+	public HavingBuilder and(FunctionType function, Column column) {
+		return getQueryBuilder().having(function, column);
+	}
+}
\ No newline at end of file