This commit is contained in:
Timo Westkämper 2008-12-08 09:33:05 +00:00
parent dac4faafe3
commit aa8f06aa82
10 changed files with 714 additions and 0 deletions

View File

@ -0,0 +1,18 @@
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/test/java" output="target/test-classes"/>
<classpathentry kind="output" path="target/classes"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="M2_REPO/net/sourceforge/collections/collections-generic/4.01/collections-generic-4.01.jar" sourcepath="M2_REPO/net/sourceforge/collections/collections-generic/4.01/collections-generic-4.01-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/commons-io/commons-io/1.4-SNAPSHOT/commons-io-1.4-SNAPSHOT.jar"/>
<classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.3/commons-lang-2.3.jar" sourcepath="M2_REPO/commons-lang/commons-lang/2.3/commons-lang-2.3-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/freemarker/freemarker/2.3.12/freemarker-2.3.12.jar" sourcepath="M2_REPO/org/freemarker/freemarker/2.3.12/freemarker-2.3.12-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/janino/janino/2.5.10/janino-2.5.10.jar"/>
<classpathentry kind="var" path="M2_REPO/junit/junit/4.4/junit-4.4.jar" sourcepath="M2_REPO/junit/junit/4.4/junit-4.4-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.14/log4j-1.2.14.jar" sourcepath="M2_REPO/log4j/log4j/1.2.14/log4j-1.2.14-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/mysema/querydsl/querydsl-apt/0.2.8-SNAPSHOT/querydsl-apt-0.2.8-SNAPSHOT.jar" sourcepath="M2_REPO/com/mysema/querydsl/querydsl-apt/0.2.8-SNAPSHOT/querydsl-apt-0.2.8-SNAPSHOT-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/mysema/querydsl/querydsl-core/0.2.8-SNAPSHOT/querydsl-core-0.2.8-SNAPSHOT.jar" sourcepath="M2_REPO/com/mysema/querydsl/querydsl-core/0.2.8-SNAPSHOT/querydsl-core-0.2.8-SNAPSHOT-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.3.1/slf4j-api-1.3.1.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.3.1/slf4j-api-1.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.3.1/slf4j-log4j12-1.3.1.jar" sourcepath="M2_REPO/org/slf4j/slf4j-log4j12/1.3.1/slf4j-log4j12-1.3.1-sources.jar"/>
<classpathentry kind="lib" path="C:/Program Files/Java/jdk1.6.0_04/lib/tools.jar"/>
</classpath>

View File

@ -0,0 +1,13 @@
<projectDescription>
<name>querydsl-collections</name>
<comment>Hibernate / HQL support for querydsl</comment>
<projects/>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,5 @@
#Sun Dec 07 13:18:28 EET 2008
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.source=1.5
org.eclipse.jdt.core.compiler.compliance=1.5

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-root</artifactId>
<version>0.2.8-SNAPSHOT</version>
</parent>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-collections</artifactId>
<name>Querydsl collections</name>
<description>Hibernate / HQL support for querydsl</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.collections</groupId>
<artifactId>collections-generic</artifactId>
<version>4.01</version>
<!-- license : Apache License 2.0 -->
</dependency>
<dependency>
<groupId>janino</groupId>
<artifactId>janino</artifactId>
<version>2.5.10</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<!-- test -->
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
<!-- license : TODO -->
</dependency>
<!-- logging -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<!-- license : Apache License 2.0 -->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.3.1</version>
<!-- license : http://www.slf4j.org/license.html -->
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,94 @@
package com.mysema.query.collections;
import java.util.*;
import org.codehaus.janino.ExpressionEvaluator;
import com.mysema.query.QueryBase;
import com.mysema.query.collections.internal.JavaSerializer;
import com.mysema.query.collections.internal.Iterators.FilteringIterator;
import com.mysema.query.collections.internal.Iterators.ProjectingIterator;
import com.mysema.query.grammar.types.Expr;
/**
* ColQuery provides
*
* @author tiwe
* @version $Id$
*/
public class ColQuery<S extends ColQuery<S>> extends QueryBase<Object,S>{
private Map<Expr<?>, Iterable<?>> entityToIterable = new HashMap<Expr<?>,Iterable<?>>();
public <RT> Iterator<RT> createIterator(Expr<RT> projection){
// from
Expr<?> source = joins.get(0).getTarget();
Iterator<?> it = null;
if (joins.size() == 1){
it = entityToIterable.get(source).iterator();
}else{
// TODO
}
// order by
if (!orderBy.isEmpty()){
// TODO
}
// where
if (where.self() != null){
try {
ExpressionEvaluator ev = new JavaSerializer().handle(where.self())
.createExpressionEvaluator(source, boolean.class);
it = new FilteringIterator<RT>(it, ev);
} catch (Exception e) {
String error = "Caught " + e.getClass().getName();
throw new RuntimeException(error, e);
}
}
// group by NOT SUPPORTED
// having NOT SUPPORTED
// select
if (source.equals(projection)){
return (Iterator<RT>)it;
}else{
try {
ExpressionEvaluator ev = new JavaSerializer().handle(projection)
.createExpressionEvaluator(source, projection);
return new ProjectingIterator<RT>(it, ev);
} catch (Exception e) {
String error = "Caught " + e.getClass().getName();
throw new RuntimeException(error, e);
}
}
}
public <A> S from(Expr.Entity<A> entity, A first, A... rest){
from(entity);
List<A> list = new ArrayList<A>(rest.length +1);
list.add(first);
list.addAll(Arrays.asList(rest));
entityToIterable.put(entity, list);
return (S)this;
}
public <A> S from(Expr.Entity<A> entity, Iterable<A> col){
from(entity);
entityToIterable.put(entity, col);
return (S)this;
}
public <RT> Iterable<RT> iterate(final Expr<RT> projection){
select(projection);
return new Iterable<RT>(){
public Iterator<RT> iterator() {
return createIterator(projection);
}
};
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2008 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.collections.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import com.mysema.query.grammar.Ops;
import com.mysema.query.grammar.Ops.Op;
import com.mysema.query.grammar.types.PathMetadata;
import com.mysema.query.grammar.types.PathMetadata.PathType;
/**
* HqlOps provides.
*
* @author tiwe
* @version $Id$
*/
public class ColOps {
private static final Map<Op<?>,java.lang.String> patterns = new HashMap<Op<?>,java.lang.String>();
static{
String functions = ColOps.class.getName();
// boolean
patterns.put(Ops.AND, "%s && %s");
patterns.put(Ops.NOT, "!%s");
patterns.put(Ops.OR, "%s || %s");
patterns.put(Ops.XNOR, "!(%s ^ %s)");
patterns.put(Ops.XOR, "%s ^ %s");
// comparison
patterns.put(Ops.BETWEEN, functions+".between(%s,%s,%s)");
patterns.put(Ops.NOTBETWEEN, "!"+functions+".between(%s,%s,%s)");
patterns.put(Ops.GOE, "%s >= %s");
patterns.put(Ops.GT, "%s > %s");
patterns.put(Ops.LOE, "%s <= %s");
patterns.put(Ops.LT, "%s < %s");
patterns.put(Ops.AFTER, "%s > %s");
patterns.put(Ops.BEFORE, "%s < %s");
// numeric
patterns.put(Ops.ADD, "%s + %s");
patterns.put(Ops.DIV, "%s / %s");
patterns.put(Ops.MOD, "%s % %s");
patterns.put(Ops.MULT,"%s * %s");
patterns.put(Ops.SUB, "%s - %s");
patterns.put(Ops.SQRT, "Math.sqrt(%s)");
// numeric aggregates
// patterns.put(OpNumberAgg.AVG, "avg(%s)");
// patterns.put(OpNumberAgg.MAX, "max(%s)");
// patterns.put(OpNumberAgg.MIN, "min(%s)");
// various
patterns.put(Ops.EQ, "%s.equals(%s)");
patterns.put(Ops.ISTYPEOF, "%s.class.equals(%s)");
patterns.put(Ops.NE, "%s != %s");
patterns.put(Ops.IN, "%2$s.contains(%1$s)");
patterns.put(Ops.NOTIN, "!%2$s.contains(%1$s)");
patterns.put(Ops.ISNULL, "%s == null");
patterns.put(Ops.ISNOTNULL, "%s != null");
// string
patterns.put(Ops.CONCAT, "%s + %s");
patterns.put(Ops.LIKE, functions+".like(%s,%s)");
patterns.put(Ops.LOWER, "%s.toLowerCase()");
patterns.put(Ops.SUBSTR1ARG, "%s.substring(%s)");
patterns.put(Ops.SUBSTR2ARGS, "%s.substring(%s,%s)");
patterns.put(Ops.TRIM, "%s.trim()");
patterns.put(Ops.UPPER, "%s.toUpperCase()");
// path types
for (PathType type : new PathType[]{PathMetadata.LISTVALUE, PathMetadata.LISTVALUE_CONSTANT, PathMetadata.MAPVALUE, PathMetadata.MAPVALUE_CONSTANT}){
patterns.put(type,"%s.get(%s)");
}
patterns.put(PathMetadata.PROPERTY,"%s.%s");
patterns.put(PathMetadata.SIZE,"%s.size()");
patterns.put(PathMetadata.VARIABLE,"%s");
}
public static java.lang.String getPattern(Op<?> op){
return patterns.get(op);
}
public static <A extends Comparable<A>> boolean between(A a, A b, A c){
return a.compareTo(b) > 0 && a.compareTo(c) < 0;
}
public static boolean like(String source, String pattern){
return Pattern.compile(pattern.replace("%", ".*")).matcher(source).matches();
}
}

View File

@ -0,0 +1,74 @@
package com.mysema.query.collections.internal;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import org.apache.commons.collections15.Predicate;
import org.apache.commons.collections15.iterators.FilterIterator;
import org.codehaus.janino.ExpressionEvaluator;
/**
* Iterators provides
*
* @author tiwe
* @version $Id$
*/
public class Iterators {
private Iterators(){}
public static class FilteringIterator<RT> extends FilterIterator<RT>{
public FilteringIterator(Iterator<?> it, final ExpressionEvaluator ev) {
super((Iterator<RT>)it, new Predicate<RT>(){
public boolean evaluate(RT object) {
try {
return (Boolean) ev.evaluate(new Object[]{object});
} catch (InvocationTargetException e) {
String error = "Caught " + e.getClass().getName();
throw new RuntimeException(error, e);
}
}
});
}
}
public abstract static class ItBase<RT> implements Iterator<RT>{
public void remove() {
}
}
public static class ProjectingIterator<RT> extends WrappingIt<RT>{
private ExpressionEvaluator ev;
public ProjectingIterator(Iterator<?> it, ExpressionEvaluator ev) {
super(it);
try {
this.ev = ev;
} catch (Exception e) {
String error = "Caught " + e.getClass().getName();
throw new RuntimeException(error, e);
}
}
public RT next() {
try {
return (RT) ev.evaluate(new Object[]{nextFromOrig()});
} catch (InvocationTargetException e) {
String error = "Caught " + e.getClass().getName();
throw new RuntimeException(error, e);
}
}
}
public abstract static class WrappingIt<RT> extends ItBase<RT>{
private Iterator<?> it;
public WrappingIt(Iterator<?> it) {
this.it = it;
}
public boolean hasNext() {
return it.hasNext();
}
protected Object nextFromOrig() {
return it.next();
}
}
}

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2008 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.collections.internal;
import static com.mysema.query.grammar.types.PathMetadata.LISTVALUE_CONSTANT;
import static com.mysema.query.grammar.types.PathMetadata.PROPERTY;
import static com.mysema.query.grammar.types.PathMetadata.VARIABLE;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.codehaus.janino.ExpressionEvaluator;
import com.mysema.query.grammar.Ops.Op;
import com.mysema.query.grammar.types.Expr;
import com.mysema.query.grammar.types.Operation;
import com.mysema.query.grammar.types.Path;
import com.mysema.query.grammar.types.VisitorAdapter;
import com.mysema.query.grammar.types.Alias.Simple;
import com.mysema.query.grammar.types.Alias.ToPath;
import com.mysema.query.grammar.types.PathMetadata.PathType;
/**
* HqlSerializer provides.
*
* @author tiwe
* @version $Id$
*/
public class JavaSerializer extends VisitorAdapter<JavaSerializer>{
private StringBuilder builder = new StringBuilder();
private List<Object> constants = new ArrayList<Object>();
private JavaSerializer _append(String str) {
builder.append(str);
return this;
}
private String _toString(Expr<?> expr, boolean wrap) {
StringBuilder old = builder;
builder = new StringBuilder();
if (wrap) builder.append("(");
handle(expr);
if (wrap) builder.append(")");
String ret = builder.toString();
builder = old;
return ret;
}
@Override
protected void visit(Expr.Constant<?> expr) {
_append("a");
if (!constants.contains(expr.getConstant())){
constants.add(expr.getConstant());
_append(Integer.toString(constants.size()));
}else{
_append(Integer.toString(constants.indexOf(expr.getConstant())+1));
}
}
@Override
protected void visit(Operation<?,?> expr) {
visitOperation(expr.getOperator(), expr.getArgs());
}
@Override
protected void visit(Path<?> path) {
PathType pathType = path.getMetadata().getPathType();
String parentAsString = null, exprAsString = null;
if (path.getMetadata().getParent() != null){
parentAsString = _toString((Expr<?>)path.getMetadata().getParent(), false);
}
if (pathType == VARIABLE){
exprAsString = path.getMetadata().getExpression().toString();
}else if (pathType == PROPERTY ){
String prefix = "get";
if (((Expr)path).getType() != null && ((Expr)path).getType().equals(Boolean.class)){
prefix = "is";
}
exprAsString = prefix+StringUtils.capitalize(path.getMetadata().getExpression().toString())+"()";
}else if (pathType == LISTVALUE_CONSTANT){
// ?!?
}else if (path.getMetadata().getExpression() != null){
exprAsString = _toString(path.getMetadata().getExpression(), false);
}
String pattern = ColOps.getPattern(pathType);
if (parentAsString != null){
_append(String.format(pattern, parentAsString, exprAsString));
}else{
_append(String.format(pattern, exprAsString));
}
}
@Override
protected void visit(Simple<?> expr) {
// TODO Auto-generated method stub
}
@Override
protected void visit(ToPath expr) {
// TODO Auto-generated method stub
}
private void visitOperation(Op<?> operator, Expr<?>... args) {
String pattern = ColOps.getPattern(operator);
if (pattern == null)
throw new IllegalArgumentException("Got no operation pattern for " + operator);
Object[] strings = new String[args.length];
for (int i = 0; i < strings.length; i++){
strings[i] = _toString(args[i], true);
}
_append(String.format(pattern, strings));
}
public ExpressionEvaluator createExpressionEvaluator(Expr<?> source, Class<?> targetType) throws Exception{
if (targetType == null) throw new IllegalArgumentException("targetType was null");
String expr = builder.toString();
System.out.println(expr);
final Object[] constArray = constants.toArray();
Class<?>[] types = new Class<?>[constArray.length+1];
String[] names = new String[constArray.length+1];
for (int i = 0; i < constArray.length; i++){
types[i] = constArray[i].getClass();
names[i] = "a" + (i+1);
}
types[types.length-1] = source.getType();
names[names.length-1] = ((Path<?>)source).getMetadata().getExpression().toString();
return new ExpressionEvaluator(expr, targetType, names, types){
@Override
public Object evaluate(Object[] origArgs) throws InvocationTargetException{
Object[] args = new Object[constArray.length + origArgs.length];
System.arraycopy(constArray, 0, args, 0, constArray.length);
System.arraycopy(origArgs, 0, args, constArray.length, origArgs.length);
return super.evaluate(args);
}
};
}
public ExpressionEvaluator createExpressionEvaluator(Expr<?> source, Expr<?> projection) throws Exception{
Class<?> targetType = projection.getType();
if (targetType == null) targetType = Object.class;
return createExpressionEvaluator(source, targetType);
}
public String toString(){ return builder.toString(); }
}

View File

@ -0,0 +1,66 @@
package com.mysema.query.collections;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.mysema.query.collections.Domain.Cat;
import com.mysema.query.collections.Domain.QCat;
import com.mysema.query.grammar.types.Expr;
/**
* ColQueryTest provides
*
* @author tiwe
* @version $Id$
*/
public class ColQueryTest {
Cat c1 = new Cat("Kitty");
Cat c2 = new Cat("Bob");
Cat c3 = new Cat("Alex");
Cat c4 = new Cat("Francis");
QCat cat = new QCat("cat");
TestQuery last;
@Test
public void test(){
query().select(cat.name);
assertTrue(last.res.size() == 4);
query().select(cat.kittens);
assertTrue(last.res.size() == 4);
query().where(cat.kittens.size().gt(0)).select(cat.name);
assertTrue(last.res.size() == 4);
query().where(cat.name.eq("Kitty")).select(cat.name);
assertTrue(last.res.size() == 1);
query().where(cat.name.like("Kitt%")).select(cat.name);
assertTrue(last.res.size() == 1);
}
private TestQuery query(){
last = new TestQuery().from(cat, c1, c2, c3, c4);
return last;
}
private static class TestQuery extends ColQuery<TestQuery>{
List<Object> res = new ArrayList<Object>();
<RT> void select(final Expr<RT> projection){
for (Object o : iterate(projection)){
System.out.println(o);
res.add(o);
}
System.out.println();
}
}
}

View File

@ -0,0 +1,115 @@
package com.mysema.query.collections;
import static com.mysema.query.grammar.types.PathMetadata.forListAccess;
import static com.mysema.query.grammar.types.PathMetadata.forProperty;
import java.util.Arrays;
import java.util.List;
import com.mysema.query.grammar.types.Expr;
import com.mysema.query.grammar.types.Path;
import com.mysema.query.grammar.types.PathMetadata;
/**
* Domain provides
*
* @author tiwe
* @version $Id$
*/
public class Domain {
public static class Animal {
boolean alive;
java.util.Date birthdate;
int bodyWeight, weight, toes;
Color color;
int id;
String name;
public java.util.Date getBirthdate() {
return birthdate;
}
public int getBodyWeight() {
return bodyWeight;
}
public Color getColor() {
return color;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getToes() {
return toes;
}
public int getWeight() {
return weight;
}
public boolean isAlive() {
return alive;
}
}
public static class Cat extends Animal{
int breed;
Color eyecolor;
List<Cat> kittens;
Cat mate;
public Cat() {}
public Cat(String name){
this.name = name;
this.kittens = Arrays.asList(new Cat());
}
public int getBreed() {
return breed;
}
public Color getEyecolor() {
return eyecolor;
}
public List<Cat> getKittens() {
return kittens;
}
public Cat getMate() {
return mate;
}
}
public enum Color {
BLACK, TABBY
}
public static class QCat extends Path.Entity<Cat>{
public final Path.Boolean alive = _boolean("alive");
public final Path.Comparable<java.util.Date> birthdate = _comparable("birthdate",java.util.Date.class);
public final Path.Comparable<java.lang.Integer> bodyWeight = _comparable("bodyWeight",java.lang.Integer.class);
public final Path.Comparable<java.lang.Integer> breed = _comparable("breed",java.lang.Integer.class);
public final Path.Simple<Color> color = _simple("color",Color.class);
public final Path.Simple<Color> eyecolor = _simple("eyecolor",Color.class);
public final Path.Comparable<java.lang.Integer> id = _comparable("id",java.lang.Integer.class);
public final Path.EntityList<Cat> kittens = _entitylist("kittens",Cat.class);
public QCat mate;
public final Path.String name = _string("name");
public final Path.Comparable<java.lang.Integer> toes = _comparable("toes",java.lang.Integer.class);
public final Path.Comparable<java.lang.Integer> weight = _comparable("weight",java.lang.Integer.class);
public QCat(java.lang.String path) {
super(Cat.class, path);
_mate();
}
public QCat(PathMetadata<?> metadata) {
super(Cat.class, metadata);
}
public QCat _mate() {
if (mate == null) mate = new QCat(forProperty(this,"mate"));
return mate;
}
public QCat kittens(Expr<Integer> index) {
return new QCat(forListAccess(kittens,index));
}
public QCat kittens(int index) {
return new QCat(forListAccess(kittens,index));
}
}
}