From 33aacb7ce8129f421d3f3f133d7f57dbb4177094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Westk=C3=A4mper?= Date: Fri, 13 Nov 2009 12:36:36 +0000 Subject: [PATCH] made CaseBuilder produce EString, ENumber and Expr types --- .../com/mysema/query/CascadingBoolean.java | 5 + .../com/mysema/query/types/CaseBuilder.java | 116 +++++++++++++++--- .../mysema/query/types/CaseBuilderTest.java | 49 ++++++-- 3 files changed, 146 insertions(+), 24 deletions(-) diff --git a/querydsl-core/src/main/java/com/mysema/query/CascadingBoolean.java b/querydsl-core/src/main/java/com/mysema/query/CascadingBoolean.java index c5c4ea17b..c6f52674c 100644 --- a/querydsl-core/src/main/java/com/mysema/query/CascadingBoolean.java +++ b/querydsl-core/src/main/java/com/mysema/query/CascadingBoolean.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2009 Mysema Ltd. + * All rights reserved. + * + */ package com.mysema.query; /** diff --git a/querydsl-core/src/main/java/com/mysema/query/types/CaseBuilder.java b/querydsl-core/src/main/java/com/mysema/query/types/CaseBuilder.java index 10e9336ff..c3854eb74 100644 --- a/querydsl-core/src/main/java/com/mysema/query/types/CaseBuilder.java +++ b/querydsl-core/src/main/java/com/mysema/query/types/CaseBuilder.java @@ -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. + * + *
+ * Expr 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");
+ * 
+ * * @author tiwe * */ @@ -30,7 +54,14 @@ public class CaseBuilder { } } - public class Cases { + /** + * Cascading typesafe Case builder + * + * @author tiwe + * + * @param + */ + public abstract static class Cases> { private final List> cases = new ArrayList>(); @@ -40,16 +71,18 @@ public class CaseBuilder { this.type = type; } - Cases addCase(EBoolean condition, Expr expr) { + Cases addCase(EBoolean condition, Expr expr) { cases.add(0, new CaseElement(condition, expr)); return this; } - public Expr otherwise(A constant) { + protected abstract Q createResult(Class type, Expr last); + + public Q otherwise(A constant) { return otherwise(ExprConst.create(constant)); } - public Expr otherwise(Expr expr) { + public Q otherwise(Expr expr) { cases.add(0, new CaseElement(null, expr)); Expr last = null; for (CaseElement element : cases){ @@ -63,50 +96,99 @@ public class CaseBuilder { last); } } - return OSimple.create(type, Ops.CASE, last); + return createResult(type, last); } - public CaseWhen when(EBoolean b) { - return new CaseWhen(this, b); + public CaseWhen when(EBoolean b) { + return new CaseWhen(this, b); } } - public class CaseWhen { + /** + * Intermediate When state + * + * @author tiwe + * + * @param + */ + public static class CaseWhen> { private final EBoolean b; - private final Cases cases; + private final Cases cases; - public CaseWhen(Cases cases, EBoolean b) { + public CaseWhen(Cases cases, EBoolean b) { this.cases = cases; this.b = b; } - public Cases then(A constant) { + public Cases then(A constant) { return then(ExprConst.create(constant)); } - public Cases then(Expr expr) { + public Cases then(Expr 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 Cases then(A constant) { + + public Cases> then(A constant) { return then(ExprConst.create(constant)); } + + public Cases then(EString expr){ + return new Cases(String.class){ + @SuppressWarnings("unchecked") + @Override + protected EString createResult(Class type, Expr last) { + return OString.create((Operator)Ops.CASE, last); + } + + }.addCase(when, expr); + } @SuppressWarnings("unchecked") - public Cases then(Expr expr) { - return new Cases((Class)expr.getType()).addCase(when, expr); + public Cases> then(Expr expr) { + return new Cases>((Class)expr.getType()){ + @Override + protected Expr createResult(Class type, Expr last) { + return OSimple.create(type, Ops.CASE, last); + } + + }.addCase(when, expr); + } + + @SuppressWarnings("unchecked") + public > Cases> then(ENumber expr) { + return new Cases>((Class)expr.getType()){ + @Override + protected ENumber createResult(Class type, Expr last) { + return ONumber.create(type, (Operator)Ops.CASE, last); + } + + }.addCase(when, expr); + } + + public Cases then(String str){ + return then(EStringConst.create(str)); + } + + public > Cases> then(A num){ + return then(ENumberConst.create(num)); } } diff --git a/querydsl-core/src/test/java/com/mysema/query/types/CaseBuilderTest.java b/querydsl-core/src/test/java/com/mysema/query/types/CaseBuilderTest.java index 322a21df0..5f14a34ae 100644 --- a/querydsl-core/src/test/java/com/mysema/query/types/CaseBuilderTest.java +++ b/querydsl-core/src/test/java/com/mysema/query/types/CaseBuilderTest.java @@ -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 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 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 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"; }