Skip to content

Commit

Permalink
#355 - ENH: Add notIn(...) expressions. Just to make life easier in t…
Browse files Browse the repository at this point in the history
…hose cases
  • Loading branch information
rbygrave committed Jul 27, 2015
1 parent 5a55b52 commit 87b485c
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 22 deletions.
17 changes: 16 additions & 1 deletion src/main/java/com/avaje/ebean/ExpressionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,22 @@ public interface ExpressionFactory {
* In - property has a value in the collection of values.
*/
Expression in(String propertyName, Collection<?> values);


/**
* Not In - property has a value in the array of values.
*/
Expression notIn(String propertyName, Object[] values);

/**
* Not In - property has a value in the collection of values.
*/
Expression notIn(String propertyName, Collection<?> values);

/**
* Not In - using a subQuery.
*/
Expression notIn(String propertyName, Query<?> subQuery);

/**
* Exists expression
*/
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/com/avaje/ebean/ExpressionList.java
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,22 @@ public interface ExpressionList<T> extends Serializable {
* In - property has a value in the collection of values.
*/
ExpressionList<T> in(String propertyName, Collection<?> values);


/**
* Not In - property has a value in the array of values.
*/
ExpressionList<T> notIn(String propertyName, Object... values);

/**
* Not In - property has a value in the collection of values.
*/
ExpressionList<T> notIn(String propertyName, Collection<?> values);

/**
* Not In - using a subQuery.
*/
ExpressionList<T> notIn(String propertyName, Query<?> subQuery);

/**
* Exists expression
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,23 +225,44 @@ public Expression icontains(String propertyName, String value) {
* In - property has a value in the array of values.
*/
public Expression in(String propertyName, Object[] values) {
return new InExpression(propertyName, values);
return new InExpression(propertyName, values, false);
}

/**
* In - using a subQuery.
*/
public Expression in(String propertyName, Query<?> subQuery) {
return new InQueryExpression(propertyName, (SpiQuery<?>) subQuery);
return new InQueryExpression(propertyName, (SpiQuery<?>) subQuery, false);
}

/**
* In - property has a value in the collection of values.
*/
public Expression in(String propertyName, Collection<?> values) {
return new InExpression(propertyName, values);
return new InExpression(propertyName, values, false);
}


/**
* In - property has a value in the array of values.
*/
public Expression notIn(String propertyName, Object[] values) {
return new InExpression(propertyName, values, true);
}

/**
* Not In - property has a value in the collection of values.
*/
public Expression notIn(String propertyName, Collection<?> values) {
return new InExpression(propertyName, values, true);
}

/**
* In - using a subQuery.
*/
public Expression notIn(String propertyName, Query<?> subQuery) {
return new InQueryExpression(propertyName, (SpiQuery<?>) subQuery, true);
}

/**
* Exists subquery
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ class InExpression extends AbstractExpression {

private static final long serialVersionUID = 3150665801693551260L;

private final boolean not;

private final Object[] values;

InExpression(String propertyName, Collection<?> coll) {
InExpression(String propertyName, Collection<?> coll, boolean not) {
super(propertyName);
values = coll.toArray(new Object[coll.size()]);
this.values = coll.toArray(new Object[coll.size()]);
this.not = not;
}

InExpression(String propertyName, Object[] array) {
InExpression(String propertyName, Object[] array, boolean not) {
super(propertyName);
this.values = array;
this.not = not;
}

public void addBindValues(SpiExpressionRequest request) {
Expand Down Expand Up @@ -50,8 +54,10 @@ public void addBindValues(SpiExpressionRequest request) {
public void addSql(SpiExpressionRequest request) {

if (values.length == 0) {
// 'no match' for in empty collection
request.append("1=0");
if (!not) {
// 'no match' for in empty collection
request.append("1=0");
}
return;
}

Expand All @@ -69,6 +75,9 @@ public void addSql(SpiExpressionRequest request) {

} else {
request.append(propertyName);
if (not) {
request.append(" not");
}
request.append(" in (?");
for (int i = 1; i < values.length; i++) {
request.append(", ").append("?");
Expand All @@ -82,7 +91,7 @@ public void addSql(SpiExpressionRequest request) {
* Based on the number of values in the in clause.
*/
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
builder.add(InExpression.class).add(propName).add(values.length);
builder.add(InExpression.class).add(propName).add(values.length).add(not);
builder.bind(values.length);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ class InQueryExpression extends AbstractExpression {

private static final long serialVersionUID = 666990277309851644L;

private final boolean not;

private final SpiQuery<?> subQuery;

private transient CQuery<?> compiledSubQuery;

public InQueryExpression(String propertyName, SpiQuery<?> subQuery) {
public InQueryExpression(String propertyName, SpiQuery<?> subQuery, boolean not) {
super(propertyName);
this.subQuery = subQuery;
this.not = not;
}

public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
builder.add(InQueryExpression.class).add(propName);

builder.add(InQueryExpression.class).add(propName).add(not);
subQuery.queryAutofetchHash(builder);
}

Expand Down Expand Up @@ -61,9 +63,11 @@ public void addSql(SpiExpressionRequest request) {
subSelect = subSelect.replace('\n', ' ');

String propertyName = getPropertyName();
request.append(" (");
request.append(propertyName);
request.append(") in (");
request.append(" (").append(propertyName).append(")");
if (not) {
request.append(" not");
}
request.append(" in (");
request.append(subSelect);
request.append(") ");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,22 @@ public ExpressionList<T> in(String propertyName, Object... values) {
public ExpressionList<T> in(String propertyName, com.avaje.ebean.Query<?> subQuery) {
return exprList.in(propertyName, subQuery);
}


@Override
public ExpressionList<T> notIn(String propertyName, Collection<?> values) {
return exprList.notIn(propertyName, values);
}

@Override
public ExpressionList<T> notIn(String propertyName, Object... values) {
return exprList.notIn(propertyName, values);
}

@Override
public ExpressionList<T> notIn(String propertyName, com.avaje.ebean.Query<?> subQuery) {
return exprList.notIn(propertyName, subQuery);
}

@Override
public ExpressionList<T> exists(Query<?> subQuery) {
return exprList.exists(subQuery);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,24 @@ public ExpressionList<T> in(String propertyName, Object... values) {
return this;
}

@Override
public ExpressionList<T> notIn(String propertyName, Object... values) {
add(expr.notIn(propertyName, values));
return this;
}

@Override
public ExpressionList<T> notIn(String propertyName, Collection<?> values) {
add(expr.notIn(propertyName, values));
return this;
}

@Override
public ExpressionList<T> notIn(String propertyName, Query<?> subQuery) {
add(expr.notIn(propertyName, subQuery));
return this;
}

@Override
public ExpressionList<T> exists(Query<?> subQuery) {
add(expr.exists(subQuery));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.avaje.ebeaninternal.server.expression;

import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.*;

public class InExpressionTest {


@Test
public void queryPlanHash_given_diffPropertyName_should_differentPlanHash() throws Exception {

List<Integer> values = values(42, 92);

InExpression ex1 = new InExpression("foo", values, false);
InExpression ex2 = new InExpression("bar", values, false);

HashQueryPlanBuilder b1 = new HashQueryPlanBuilder();
ex1.queryPlanHash(null, b1);

HashQueryPlanBuilder b2 = new HashQueryPlanBuilder();
ex2.queryPlanHash(null, b2);

assertNotEquals(b1.build(), b2.build());
}

@Test
public void queryPlanHash_given_diffBindCount_should_differentPlanHash() throws Exception {

List<Integer> values1 = values(42, 92);
List<Integer> values2 = values(42, 92, 82);

InExpression ex1 = new InExpression("foo", values1, false);
InExpression ex2 = new InExpression("foo", values2, false);

HashQueryPlanBuilder b1 = new HashQueryPlanBuilder();
ex1.queryPlanHash(null, b1);

HashQueryPlanBuilder b2 = new HashQueryPlanBuilder();
ex2.queryPlanHash(null, b2);

assertNotEquals(b1.build(), b2.build());
}

@Test
public void queryPlanHash_given_diffNotFlag_should_differentPlanHash() throws Exception {

List<Integer> values = values(42, 92);

InExpression ex1 = new InExpression("foo", values, true);
InExpression ex2 = new InExpression("foo", values, false);

HashQueryPlanBuilder b1 = new HashQueryPlanBuilder();
ex1.queryPlanHash(null, b1);

HashQueryPlanBuilder b2 = new HashQueryPlanBuilder();
ex2.queryPlanHash(null, b2);

assertNotEquals(b1.build(), b2.build());
}

@Test
public void queryPlanHash_given_sameNotFlag_should_samePlanHash() throws Exception {

List<Integer> values = values(42, 92);

InExpression ex1 = new InExpression("foo", values, true);
InExpression ex2 = new InExpression("foo", values, true);

HashQueryPlanBuilder b1 = new HashQueryPlanBuilder();
ex1.queryPlanHash(null, b1);

HashQueryPlanBuilder b2 = new HashQueryPlanBuilder();
ex2.queryPlanHash(null, b2);

assertEquals(b1.build(), b2.build());
}

List<Integer> values(int... vals) {
ArrayList list = new ArrayList<Integer>();
for (int i = 0; i < vals.length; i++) {
list.add(vals[i]);
}
return list;
}
}
34 changes: 31 additions & 3 deletions src/test/java/com/avaje/tests/query/TestQueryAlias.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
import com.avaje.tests.model.basic.ResetBasicData;

public class TestQueryAlias extends BaseTestCase {

@Test
public void testExists() {

ResetBasicData.reset();

Query<CKeyParent> sq = Ebean.createQuery(CKeyParent.class)
Expand All @@ -24,15 +26,41 @@ public void testExists() {

String sql = pq.getGeneratedSql();

System.out.println(sql);
// Without alias command is should be:
// select t0.one_key c0, t0.two_key c1, t0.name c2, t0.version c3, t0.assoc_id c4 from ckey_parent t0 where (t0
// .one_key) in (select t0.one_key from ckey_parent t0)
// but with alias command SQL should look like this:
// select myt0.one_key c0, myt0.two_key c1, myt0.name c2, myt0.version c3, myt0.assoc_id c4 from ckey_parent myt0
// where (myt0.one_key) in (select st0.one_key from ckey_parent st0)

Assert.assertTrue(sql.indexOf("ckey_parent myt0") > 0);
Assert.assertTrue(sql.indexOf("in (select st0.one_key from ckey_parent st0)") > 0);
Assert.assertTrue(sql.contains("ckey_parent myt0"));
Assert.assertTrue(sql.contains("(myt0.one_key) in (select st0.one_key from ckey_parent st0)"));
}

@Test
public void testNotExists() {

ResetBasicData.reset();

Query<CKeyParent> sq = Ebean.createQuery(CKeyParent.class)
.select("id.oneKey").alias("st0")
.setAutofetch(false).where().query();

Query<CKeyParent> pq = Ebean.find(CKeyParent.class).alias("myt0").where().notIn("id.oneKey", sq).query();

pq.findList();

String sql = pq.getGeneratedSql();

// Without alias command is should be:
// select t0.one_key c0, t0.two_key c1, t0.name c2, t0.version c3, t0.assoc_id c4 from ckey_parent t0 where (t0
// .one_key) in (select t0.one_key from ckey_parent t0)
// but with alias command SQL should look like this:
// select myt0.one_key c0, myt0.two_key c1, myt0.name c2, myt0.version c3, myt0.assoc_id c4 from ckey_parent myt0
// where (myt0.one_key) in (select st0.one_key from ckey_parent st0)

Assert.assertTrue(sql.contains("ckey_parent myt0"));
Assert.assertTrue(sql.contains("(myt0.one_key) not in (select st0.one_key from ckey_parent st0)"));
}

}

0 comments on commit 87b485c

Please sign in to comment.