Implement SELECT DISTINCT [ON <exp>] as a QueryClause.

This commit is contained in:
Par Winzell
2012-02-03 21:29:16 +00:00
parent 03ee53194b
commit cf47c335a0
7 changed files with 79 additions and 0 deletions
@@ -178,6 +178,25 @@ public class Query<T extends PersistentRecord>
return query;
}
/**
* Configures the query to return only distinct rows.
*/
public Query<T> distinct ()
{
return distinct(null);
}
/**
* Configures the query to return rows for which the given expression evaluates distinctly.
*/
public Query<T> distinct (SQLExpression<?> distinctOn)
{
checkState(_distinct == null, "Distinct clause is already configured.");
Query<T> query = clone();
query._distinct = new Distinct(distinctOn);
return query;
}
/**
* Configures a {@link GroupBy} clause on the supplied group expressions.
*/
@@ -610,6 +629,7 @@ public class Query<T extends PersistentRecord>
addIfNotNull(clauses, _where);
addAll(clauses, _joins);
addIfNotNull(clauses, _orderBy);
addIfNotNull(clauses, _distinct);
addIfNotNull(clauses, _groupBy);
addIfNotNull(clauses, _limit);
addIfNotNull(clauses, _fromOverride);
@@ -636,6 +656,7 @@ public class Query<T extends PersistentRecord>
checkState(_where != null, "Where clause must be specified for delete.");
checkState(_joins == null, "Join clauses not supported by delete.");
checkState(_orderBy == null, "OrderBy clause not applicable for delete.");
checkState(_distinct == null, "Distinct clause not applicable for delete.");
checkState(_groupBy == null, "GroupBy clause not applicable for delete.");
checkState(_fromOverride == null, "FromOverride clause not applicable for delete.");
checkState(_fieldDefs == null, "FieldDefinition clauses not applicable for delete.");
@@ -678,6 +699,7 @@ public class Query<T extends PersistentRecord>
protected WhereClause _where;
protected OrderBy _orderBy;
protected Distinct _distinct;
protected GroupBy _groupBy;
protected Limit _limit;
protected FromOverride _fromOverride;
@@ -64,6 +64,10 @@ public class SelectClause
} else if (clause instanceof FieldDefinition) {
_disMap.put(((FieldDefinition) clause).getField(), ((FieldDefinition) clause));
} else if (clause instanceof Distinct) {
checkArgument(_orderBy == null, "Query can't contain multiple Distinct clauses.");
_distinct = (Distinct) clause;
} else if (clause instanceof OrderBy) {
checkArgument(_orderBy == null, "Query can't contain multiple OrderBy clauses.");
_orderBy = (OrderBy) clause;
@@ -128,6 +132,11 @@ public class SelectClause
return _orderBy;
}
public Distinct getDistinct ()
{
return _distinct;
}
public GroupBy getGroupBy ()
{
return _groupBy;
@@ -182,6 +191,9 @@ public class SelectClause
if (_orderBy != null) {
builder.append(", orderBy=").append(_orderBy);
}
if (_distinct != null) {
builder.append(", distinct=").append(_distinct);
}
if (_groupBy != null) {
builder.append(", groupBy=").append(_groupBy);
}
@@ -215,6 +227,9 @@ public class SelectClause
/** The order by clause, if any. */
protected OrderBy _orderBy;
/** The distinct clause, if any. */
protected Distinct _distinct;
/** The group by clause, if any. */
protected GroupBy _groupBy;
@@ -14,6 +14,7 @@ import java.util.Set;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.samskivert.depot.clause.Distinct;
import com.samskivert.util.ByteEnum;
import com.samskivert.util.Tuple;
@@ -278,6 +279,17 @@ public abstract class BuildVisitor implements FragmentVisitor<Void>
return null;
}
public Void visit (Distinct distinct)
{
_builder.append("distinct ");
if (distinct.getDistinctOn() != null) {
_builder.append("on ");
distinct.getDistinctOn().accept(this);
_builder.append(" ");
}
return null;
}
public Void visit (Join join)
{
switch (join.getType()) {
@@ -345,6 +357,10 @@ public abstract class BuildVisitor implements FragmentVisitor<Void>
checkArgument(!_definitions.containsKey(pClass),
"Can not yet nest SELECTs on the same persistent record.");
if (selectClause.getDistinct() != null) {
selectClause.getDistinct().accept(this);
}
Map<String, FieldDefinition> definitionMap = Maps.newHashMap();
for (FieldDefinition definition : selectClause.getFieldDefinitions()) {
definitionMap.put(definition.getField(), definition);
@@ -9,6 +9,7 @@ import java.lang.reflect.Field;
import com.samskivert.depot.Key;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.clause.Distinct;
import com.samskivert.depot.clause.FieldDefinition;
import com.samskivert.depot.clause.ForUpdate;
import com.samskivert.depot.clause.FromOverride;
@@ -252,6 +253,11 @@ public class ExpressionEvaluator
throw new IllegalArgumentException("Can't evaluate expression: " + exists);
}
public Object visit (Distinct distinct)
{
throw new IllegalArgumentException("Can't evaluate expression: " + distinct);
}
public Object visit (GroupBy groupBy)
{
throw new IllegalArgumentException("Can't evaluate expression: " + groupBy);
@@ -6,6 +6,7 @@ package com.samskivert.depot.impl;
import com.samskivert.depot.Key;
import com.samskivert.depot.clause.Distinct;
import com.samskivert.depot.clause.FieldDefinition;
import com.samskivert.depot.clause.ForUpdate;
import com.samskivert.depot.clause.FromOverride;
@@ -81,6 +82,7 @@ public interface FragmentVisitor<T>
public T visit (FullText.Rank match);
public T visit (ColumnExp<?> columnExp);
public T visit (Not not);
public T visit (Distinct distinct);
public T visit (GroupBy groupBy);
public T visit (ForUpdate forUpdate);
public T visit (OrderBy orderBy);
@@ -18,6 +18,7 @@ import com.samskivert.depot.Ops;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.annotation.FullTextIndex;
import com.samskivert.depot.annotation.GeneratedValue;
import com.samskivert.depot.clause.Distinct;
import com.samskivert.depot.clause.OrderBy;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.SQLExpression;
@@ -132,6 +133,14 @@ public class HSQLBuilder
return super.visit(operator);
}
public Void visit (Distinct distinct)
{
if (distinct.getDistinctOn() != null) {
throw new IllegalArgumentException("MySQL does not support DISTINCT ON");
}
return super.visit(distinct);
}
@Override public Void visit (DatePart exp) {
if (exp.getPart() == Part.EPOCH) {
@@ -10,6 +10,7 @@ import java.sql.SQLException;
import java.util.Map;
import java.util.Set;
import com.samskivert.depot.clause.Distinct;
import com.samskivert.util.StringUtil;
import com.samskivert.depot.PersistentRecord;
@@ -69,6 +70,14 @@ public class MySQLBuilder
return appendFunctionCall("truncate", exp.getArg());
}
public Void visit (Distinct distinct)
{
if (distinct.getDistinctOn() != null) {
throw new IllegalArgumentException("MySQL does not support DISTINCT ON");
}
return super.visit(distinct);
}
@Override public Void visit (DatePart exp) {
return appendFunctionCall(getDateFunction(exp.getPart()), exp.getArg());
}