made CaseBuilder produce EString, ENumber and Expr types

This commit is contained in:
Timo Westkämper 2009-11-13 12:36:36 +00:00
parent c8a1e1d841
commit 33aacb7ce8
3 changed files with 146 additions and 24 deletions

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query;
/**

View File

@ -1,3 +1,8 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.types;
import java.util.ArrayList;
@ -6,12 +11,31 @@ import java.util.List;
import javax.annotation.Nullable;
import com.mysema.query.types.expr.EBoolean;
import com.mysema.query.types.expr.ENumber;
import com.mysema.query.types.expr.ENumberConst;
import com.mysema.query.types.expr.EString;
import com.mysema.query.types.expr.EStringConst;
import com.mysema.query.types.expr.Expr;
import com.mysema.query.types.expr.ExprConst;
import com.mysema.query.types.operation.ONumber;
import com.mysema.query.types.operation.OSimple;
import com.mysema.query.types.operation.OString;
import com.mysema.query.types.operation.Operator;
import com.mysema.query.types.operation.Ops;
/**
* CaseBuilder enables the construction of typesafe case-when-then-else
* constructs :
* e.g.
*
* <pre>
* Expr<String> cases = new CaseBuilder()
* .when(c.annualSpending.gt(10000)).then("Premier")
* .when(c.annualSpending.gt(5000)).then("Gold")
* .when(c.annualSpending.gt(2000)).then("Silver")
* .otherwise("Bronze");
* </pre>
*
* @author tiwe
*
*/
@ -30,7 +54,14 @@ public class CaseBuilder {
}
}
public class Cases<A> {
/**
* Cascading typesafe Case builder
*
* @author tiwe
*
* @param <A>
*/
public abstract static class Cases<A, Q extends Expr<A>> {
private final List<CaseElement<A>> cases = new ArrayList<CaseElement<A>>();
@ -40,16 +71,18 @@ public class CaseBuilder {
this.type = type;
}
Cases<A> addCase(EBoolean condition, Expr<A> expr) {
Cases<A,Q> addCase(EBoolean condition, Expr<A> expr) {
cases.add(0, new CaseElement<A>(condition, expr));
return this;
}
public Expr<A> otherwise(A constant) {
protected abstract Q createResult(Class<A> type, Expr<A> last);
public Q otherwise(A constant) {
return otherwise(ExprConst.create(constant));
}
public Expr<A> otherwise(Expr<A> expr) {
public Q otherwise(Expr<A> expr) {
cases.add(0, new CaseElement<A>(null, expr));
Expr<A> last = null;
for (CaseElement<A> element : cases){
@ -63,50 +96,99 @@ public class CaseBuilder {
last);
}
}
return OSimple.create(type, Ops.CASE, last);
return createResult(type, last);
}
public CaseWhen<A> when(EBoolean b) {
return new CaseWhen<A>(this, b);
public CaseWhen<A,Q> when(EBoolean b) {
return new CaseWhen<A,Q>(this, b);
}
}
public class CaseWhen<A> {
/**
* Intermediate When state
*
* @author tiwe
*
* @param <A>
*/
public static class CaseWhen<A,Q extends Expr<A>> {
private final EBoolean b;
private final Cases<A> cases;
private final Cases<A,Q> cases;
public CaseWhen(Cases<A> cases, EBoolean b) {
public CaseWhen(Cases<A,Q> cases, EBoolean b) {
this.cases = cases;
this.b = b;
}
public Cases<A> then(A constant) {
public Cases<A,Q> then(A constant) {
return then(ExprConst.create(constant));
}
public Cases<A> then(Expr<A> expr) {
public Cases<A,Q> then(Expr<A> expr) {
return cases.addCase(b, expr);
}
}
public class Initial {
/**
* Initial state of Case construction
*
* @author tiwe
*
*/
public static class Initial {
private final EBoolean when;
public Initial(EBoolean b) {
this.when = b;
}
public <A> Cases<A> then(A constant) {
public <A> Cases<A,Expr<A>> then(A constant) {
return then(ExprConst.create(constant));
}
public Cases<String,EString> then(EString expr){
return new Cases<String,EString>(String.class){
@SuppressWarnings("unchecked")
@Override
protected EString createResult(Class<String> type, Expr<String> last) {
return OString.create((Operator)Ops.CASE, last);
}
}.addCase(when, expr);
}
@SuppressWarnings("unchecked")
public <A> Cases<A> then(Expr<A> expr) {
return new Cases<A>((Class)expr.getType()).addCase(when, expr);
public <A> Cases<A, Expr<A>> then(Expr<A> expr) {
return new Cases<A,Expr<A>>((Class)expr.getType()){
@Override
protected Expr<A> createResult(Class<A> type, Expr<A> last) {
return OSimple.create(type, Ops.CASE, last);
}
}.addCase(when, expr);
}
@SuppressWarnings("unchecked")
public <A extends Number & Comparable<?>> Cases<A, ENumber<A>> then(ENumber<A> expr) {
return new Cases<A, ENumber<A>>((Class)expr.getType()){
@Override
protected ENumber<A> createResult(Class<A> type, Expr<A> last) {
return ONumber.create(type, (Operator)Ops.CASE, last);
}
}.addCase(when, expr);
}
public Cases<String, EString> then(String str){
return then(EStringConst.create(str));
}
public <A extends Number & Comparable<?>> Cases<A, ENumber<A>> then(A num){
return then(ENumberConst.create(num));
}
}

View File

@ -1,11 +1,18 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.types;
import static com.mysema.query.alias.Alias.$;
import static com.mysema.query.alias.Alias.alias;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.mysema.query.types.expr.ENumber;
import com.mysema.query.types.expr.EString;
import com.mysema.query.types.expr.Expr;
public class CaseBuilderTest {
@ -18,7 +25,39 @@ public class CaseBuilderTest {
}
@Test
public void test(){
public void booleanTyped(){
Customer c = alias(Customer.class, "customer");
Expr<Boolean> cases = new CaseBuilder()
.when($(c.getAnnualSpending()).gt(10000)).then(true)
.otherwise(false);
assertEquals(
"case " +
"when customer.annualSpending > 10000 then true " +
"else false " +
"end", cases.toString());
}
@Test
public void numberTyped(){
Customer c = alias(Customer.class, "customer");
ENumber<Integer> cases = new CaseBuilder()
.when($(c.getAnnualSpending()).gt(10000)).then(1)
.when($(c.getAnnualSpending()).gt(5000)).then(2)
.when($(c.getAnnualSpending()).gt(2000)).then(3)
.otherwise(4);
assertEquals(
"case " +
"when customer.annualSpending > 10000 then 1 " +
"when customer.annualSpending > 5000 then 2 " +
"when customer.annualSpending > 2000 then 3 " +
"else 4 " +
"end", cases.toString());
}
@Test
public void stringTyped(){
// CASE
// WHEN c.annualSpending > 10000 THEN 'Premier'
// WHEN c.annualSpending > 5000 THEN 'Gold'
@ -27,7 +66,7 @@ public class CaseBuilderTest {
// END
Customer c = alias(Customer.class, "customer");
Expr<String> cases = new CaseBuilder()
EString cases = new CaseBuilder()
.when($(c.getAnnualSpending()).gt(10000)).then("Premier")
.when($(c.getAnnualSpending()).gt(5000)).then("Gold")
.when($(c.getAnnualSpending()).gt(2000)).then("Silver")
@ -42,10 +81,6 @@ public class CaseBuilderTest {
"else Bronze " +
"end", cases.toString());
String rv = c.getAnnualSpending() > 10000 ? "Premier" :
c.getAnnualSpending() > 5000 ? "Gold" :
c.getAnnualSpending() > 2000 ? "Silver" :
"Bronze";
}