Skip to content

Commit

Permalink
#423 Add left join support
Browse files Browse the repository at this point in the history
  • Loading branch information
timowest committed May 25, 2013
1 parent f49a44b commit 108bff3
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 6 deletions.
Expand Up @@ -149,6 +149,32 @@ public <P> Q innerJoin(MapExpression<?,P> target, Path<P> alias) {
getMetadata().addJoin(JoinType.INNERJOIN, createAlias(target, alias));
return (Q)this;
}

/**
* Define a left join from the Collection typed path to the alias
*
* @param <P>
* @param collectionPath
* @param alias
* @return
*/
public <P> Q leftJoin(Path<? extends Collection<P>> target, Path<P> alias) {
getMetadata().addJoin(JoinType.LEFTJOIN, createAlias(target, alias));
return (Q)this;
}

/**
* Define a left join from the Map typed path to the alias
*
* @param <P>
* @param mapPath
* @param alias
* @return
*/
public <P> Q leftJoin(MapExpression<?,P> target, Path<P> alias) {
getMetadata().addJoin(JoinType.LEFTJOIN, createAlias(target, alias));
return (Q)this;
}

@Override
public CloseableIterator<Tuple> iterate(Expression<?>... args) {
Expand Down
Expand Up @@ -14,8 +14,11 @@
package com.mysema.query.collections;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.annotation.Nullable;

Expand All @@ -29,6 +32,8 @@
*/
public final class CollQueryFunctions {

private static final List<Object> nullList = Arrays.<Object>asList((Object)null);

public static <A extends Comparable<? super A>> boolean between(A a, A b, A c) {
return a.compareTo(b) >= 0 && a.compareTo(c) <= 0;
}
Expand Down Expand Up @@ -122,7 +127,15 @@ public static int getYearMonth(Date date) {
cal.setTime(date);
return cal.get(Calendar.YEAR) * 100 + cal.get(Calendar.MONTH) + 1;
}


public static <T> Collection<T> leftJoin(Collection<T> coll) {
if (coll.isEmpty()) {
return (List) nullList;
} else {
return coll;
}
}

public static boolean like(final String str, String like) {
final StringBuilder pattern = new StringBuilder(like.length() + 4);
for (int i = 0; i < like.length(); i++) {
Expand Down
Expand Up @@ -187,23 +187,30 @@ public Evaluator<List<Object[]>> createEvaluator(QueryMetadata metadata,
if (vars.length() > 0) {
vars.append(",");
}
if (join.getType() == JoinType.DEFAULT) {
switch (join.getType()) {
case DEFAULT:
ser.append("for (" + typeName + " "+ target + " : " + target + "_) {\n");
vars.append(target);
sourceNames.add(target+"_");
sourceTypes.add(new SimpleType(Types.ITERABLE, new ClassType(TypeCategory.SIMPLE,target.getType())));
sourceClasses.add(Iterable.class);
break;

} else if (join.getType() == JoinType.INNERJOIN) {
case INNERJOIN:
case LEFTJOIN:
Operation alias = (Operation)join.getTarget();
boolean colAnyJoin = join.getCondition() != null && join.getCondition().toString().equals("any");
boolean leftJoin = join.getType() == JoinType.LEFTJOIN;
String matcher = null;
if (colAnyJoin) {
matcher = alias.getArg(1).toString() + "_matched";
ser.append("boolean " + matcher + " = false;\n");
anyJoinMatchers.add(matcher);
}
ser.append("for (" + typeName + " " + alias.getArg(1) + " : ");
if (leftJoin) {
ser.append(CollQueryFunctions.class.getName()+".leftJoin(");
}
if (colAnyJoin) {
Context context = new Context();
Expression<?> replacement = (Expression<?>) alias.getArg(0)
Expand All @@ -215,13 +222,17 @@ public Evaluator<List<Object[]>> createEvaluator(QueryMetadata metadata,
if (alias.getArg(0).getType().equals(Map.class)) {
ser.append(".values()");
}
if (leftJoin) {
ser.append(")");
}
ser.append(") {\n");
if (matcher != null) {
ser.append("if (!" + matcher + ") {\n");
}
vars.append(alias.getArg(1));

} else {
break;

default:
throw new IllegalArgumentException("Illegal join expression " + join);
}
}
Expand All @@ -248,7 +259,7 @@ public Evaluator<List<Object[]>> createEvaluator(QueryMetadata metadata,

Map<Object,String> constantToLabel = ser.getConstantToLabel();
Map<String, Object> constants = getConstants(metadata, constantToLabel);

ClassType projectionType = new ClassType(TypeCategory.LIST, List.class, Types.OBJECTS);
return factory.createEvaluator(
ser.toString(),
Expand Down
@@ -0,0 +1,87 @@
/*
* Copyright 2011, Mysema Ltd
*
* Licensed 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 com.mysema.query.collections;

import static com.mysema.query.alias.Alias.$;
import static com.mysema.query.alias.Alias.alias;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

public class LeftJoinTest extends AbstractQueryTest {

private QCat cat, kitten;

private List<Cat> cats;

@Before
public void setUp() {
super.setUp();
cat = new QCat("c");
kitten = new QCat("k");
Cat bob = new Cat("Bob");
Cat bob2 = new Cat("Bob");
Cat kate = new Cat("Kate");
Cat kate2 = new Cat("Kate");
Cat franz = new Cat("Franz");

bob.setKittens(Collections.singletonList(bob2));
bob.setKittensByName(Collections.singletonMap(bob2.getName(), bob2));
kate.setKittens(Collections.<Cat>emptyList());
kate.setKittensByName(Collections.singletonMap(kate2.getName(), kate));
cats = Arrays.asList(bob, bob2, kate, kate2, franz);
}

@Test
public void List() {
List<Cat> rv = CollQueryFactory.from(cat, cats)
.leftJoin(cat.kittens, kitten)
.where(kitten.isNotNull(), cat.name.eq(kitten.name))
.orderBy(cat.name.asc())
.list(cat);

assertEquals(1, rv.size());
assertEquals("Bob", rv.get(0).getName());
}

@Test
public void Alias() {
Cat cc = alias(Cat.class, "cat1");
Cat ck = alias(Cat.class, "cat2");
List<Cat> rv = CollQueryFactory.from($(cc), cats)
.leftJoin($(cc.getKittens()), $(ck))
.where($(ck).isNotNull(), $(cc.getName()).eq($(ck.getName())))
.list($(cc));
assertFalse(rv.isEmpty());
}


@Test
public void Map() {
List<Cat> rv = CollQueryFactory.from(cat, cats)
.leftJoin(cat.kittensByName, kitten)
.where(cat.name.eq(kitten.name))
.orderBy(cat.name.asc())
.list(cat);
assertEquals("Bob", rv.get(0).getName());
assertEquals("Kate", rv.get(1).getName());
}

}

0 comments on commit 108bff3

Please sign in to comment.