diff --git a/querydsl-scala/.cache b/querydsl-scala/.cache index b8afccdee..b1c75fd61 100644 Binary files a/querydsl-scala/.cache and b/querydsl-scala/.cache differ diff --git a/querydsl-scala/src/main/scala/com/mysema/query/scala/EntitySerializer.scala b/querydsl-scala/src/main/scala/com/mysema/query/scala/EntitySerializer.scala index 28a85af69..2d7be06c8 100644 --- a/querydsl-scala/src/main/scala/com/mysema/query/scala/EntitySerializer.scala +++ b/querydsl-scala/src/main/scala/com/mysema/query/scala/EntitySerializer.scala @@ -129,17 +129,15 @@ class ScalaEntitySerializer @Inject()(val typeMappings: TypeMappings) extends Se case LIST | SET | COLLECTION => { val componentType = writer.getGenericName(true, property.getParameter(0)) val queryType = typeMappings.getPathType(getRaw(property.getParameter(0)), model, false) - methodName + "(\"" + property.getName + "\", classOf[" + componentType + "], classOf[" + - writer.getGenericName(true, queryType) + "])" + methodName + "["+componentType+","+writer.getGenericName(true, queryType)+"](\"" + property.getName + "\")" } case MAP => { val keyType = writer.getGenericName(true, property.getParameter(0)) val valueType = writer.getGenericName(true, property.getParameter(1)) val queryType = typeMappings.getPathType(getRaw(property.getParameter(1)), model, false) - methodName + "(\"" + property.getName + "\", classOf[" + keyType + "], classOf[" + valueType + "], classOf[" + - writer.getGenericName(true, queryType) + "])" + methodName + "["+keyType+","+valueType+","+writer.getGenericName(true, queryType)+"](\"" + property.getName + "\")" } - case _ => methodName + "(\"" + property.getName + "\", classOf[" + writer.getRawName(property.getType) + "])" + case _ => methodName + "[" + writer.getRawName(property.getType) + "](\"" + property.getName + "\")" } (property.getEscapedName, value) } diff --git a/querydsl-scala/src/main/scala/com/mysema/query/scala/Paths.scala b/querydsl-scala/src/main/scala/com/mysema/query/scala/Paths.scala index b3ba76913..1b391c1e4 100644 --- a/querydsl-scala/src/main/scala/com/mysema/query/scala/Paths.scala +++ b/querydsl-scala/src/main/scala/com/mysema/query/scala/Paths.scala @@ -6,6 +6,7 @@ import com.mysema.query.codegen._; import com.mysema.codegen.model.TypeCategory +import com.mysema.scala.ManifestUtils._ import TypeDefs._ /** @@ -17,7 +18,7 @@ import TypeDefs._ object Paths { type Metadata[X] = PathMetadata[X] - + def array[T <: Array[_]](t: Class[T], md: Metadata[_]) = new ArrayPath[T](t, md) def simple[T](t: Class[_ <: T], md: Metadata[_]) = new SimplePath[T](t, md) @@ -76,40 +77,42 @@ class ArrayPath[T <: Array[_]](t: Class[T], md: PathMetadata[_]) class BeanPath[T](t: Class[_ <: T], md: PathMetadata[_]) extends PathImpl[T](t, md) with SimpleExpression[T] { - + import Paths._ + type Mf[X] = Manifest[X] + def add[P <: Path[_]](path: P): P = path - def createArray[T <: Array[_]](property: String, t: Class[T]) = add(array(t, forProperty(property))) + def createArray[T <: Array[_]](property: String)(implicit mf: Mf[T]) = add(array(mf, forProperty(property))) - def createSimple[T](property: String, t: Class[T]) = add(simple(t, forProperty(property))) + def createSimple[T](property: String)(implicit mf: Mf[T]) = add(simple(mf, forProperty(property))) - def createEntity[T](property: String, t: Class[T]) = add(entity(t, forProperty(property))) + def createEntity[T](property: String)(implicit mf: Mf[T]) = add(entity(t, forProperty(property))) - def createCollection[T, Q <: Ex[_ >: T]](property: String, t: Class[T], q: Class[Q]) = add(collection(t, q, forProperty(property))) + def createCollection[T, Q <: Ex[_ >: T]](property: String)(implicit t: Mf[T], q: Mf[Q]) = add(collection(t, q, forProperty(property))) - def createSet[T, Q <: Ex[_ >: T]](property: String, t: Class[T], q: Class[Q]) = add(set(t, q, forProperty(property))) + def createSet[T, Q <: Ex[_ >: T]](property: String)(implicit t: Mf[T], q: Mf[Q]) = add(set(t, q, forProperty(property))) - def createList[T, Q <: Ex[_ >: T]](property: String, t: Class[T], q: Class[Q]) = add(list(t, q, forProperty(property))) + def createList[T, Q <: Ex[_ >: T]](property: String)(implicit t: Mf[T], q: Mf[Q]) = add(list(t, q, forProperty(property))) - def createMap[K, V, Q <: Ex[_ >: V]](property: String, k: Class[K], v: Class[V], q: Class[Q]) = add(map(k, v, q, forProperty(property))) + def createMap[K, V, Q <: Ex[_ >: V]](property: String)(implicit k: Mf[K], v: Mf[V], q: Mf[Q]) = add(map(k, v, q, forProperty(property))) - def createComparable[T <: Comparable[_]](property: String, t: Class[T]) = add(comparable(t, forProperty(property))) + def createComparable[T <: Comparable[_]](property: String)(implicit mf: Mf[T]) = add(comparable(mf, forProperty(property))) - def createDate[T <: Comparable[_]](property: String, t: Class[T]) = add(date(t, forProperty(property))) + def createDate[T <: Comparable[_]](property: String)(implicit mf: Mf[T]) = add(date(mf, forProperty(property))) - def createDateTime[T <: Comparable[_]](property: String, t: Class[T]) = add(dateTime(t, forProperty(property))) + def createDateTime[T <: Comparable[_]](property: String)(implicit mf: Mf[T]) = add(dateTime(mf, forProperty(property))) - def createTime[T <: Comparable[_]](property: String, t: Class[T]) = add(time(t, forProperty(property))) + def createTime[T <: Comparable[_]](property: String)(implicit mf: Mf[T]) = add(time(mf, forProperty(property))) - def createNumber[T <: Number with Comparable[T]](property: String, t: Class[T]) = add(number(t, forProperty(property))) + def createNumber[T <: Number with Comparable[T]](property: String)(implicit mf: Mf[T]) = add(number(mf, forProperty(property))) def createBoolean(property: String) = add(boolean(forProperty(property))) def createString(property: String) = add(string(forProperty(property))) - def createEnum[T <: Enum[T]](property: String, t: Class[T]) = add(enum(t, forProperty(property))) + def createEnum[T <: Enum[T]](property: String)(implicit mf: Mf[T]) = add(enum(mf, forProperty(property))) private def forProperty(property: String) = PathMetadataFactory.forProperty(this, property) diff --git a/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Paths.scala b/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Paths.scala index 84d6c098d..838eb50f7 100644 --- a/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Paths.scala +++ b/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Paths.scala @@ -1,4 +1,6 @@ package com.mysema.query.scala.sql; + +import com.mysema.scala.ReflectionUtils._ import com.mysema.query.scala.BeanPath import com.mysema.query.sql._ import com.mysema.query.types._ @@ -7,6 +9,7 @@ import java.util.ArrayList; import java.lang.reflect._ import scala.reflect.BeanProperty import com.mysema.query.scala.TypeDefs._ +import scala.collection.JavaConversions.mapAsJavaMap /** * Implementation of RelationsPathImpl for Scala @@ -30,19 +33,18 @@ class RelationalPathImpl[T](md: PathMetadata[_], schema: String, table: String)( @BeanProperty val inverseForeignKeys: JList[ForeignKey[_]] = new ArrayList[ForeignKey[_]] - // TODO : implementation into Utility class @BeanProperty - lazy val projection: FactoryExpression[T] = { + lazy val projection: FactoryExpression[T] = { val rp = RelationalPathImpl.this - val bindings = new java.util.HashMap[String, Ex[_]] - def supers(cl: Class[_]): List[Class[_]] = cl :: Option(cl.getSuperclass).map(supers).getOrElse(Nil) - supers(getClass).flatMap(_.getDeclaredFields) + val bindings = getFields(getClass()) + // only non static Path typed fields .filter(f => classOf[Path[_]].isAssignableFrom(f.getType) && !Modifier.isStatic(f.getModifiers)) - .foreach(f => { - f.setAccessible(true) - val col = f.get(rp).asInstanceOf[Path[_]] - if (rp == col.getMetadata.getParent) bindings.put(f.getName, col) - }) + // map to property,value tuples + .map(f => getNameAndValue[Path[_]](rp,f)) + // filter non related tuples out + .filter(rp == _._2.getMetadata.getParent) + .toMap + new QBean[T](getType.asInstanceOf[Class[T]], true, bindings) } diff --git a/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Queries.scala b/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Queries.scala index 44e220f6a..f46977d88 100644 --- a/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Queries.scala +++ b/querydsl-scala/src/main/scala/com/mysema/query/scala/sql/Queries.scala @@ -11,6 +11,16 @@ import com.mysema.query.scala.TypeDefs._ import com.mysema.query.scala.RichProjectable import com.mysema.query.scala.Projections._ +/** + * RichSimpleQuery provides a simplied query DSL for Querydsl SQL + Scala + * + * @author tiwe + * + * @param + * @param

+ * @param + * @param + */ class RichSimpleQuery[PT, P <: RelationalPath[PT], T, E <: Ex[T]](path: P, expr: E, qry: SQLQuery) extends RichProjectable(qry) { @@ -88,7 +98,7 @@ object ExprToTarget { implicit def pathToTuple2[T,E <: RP[T],T2,E2 <: RP[T2]] = { new ExprToTarget[T,E,T2,E2,(T,T2),Tu2Ex[T,T2]]() { - def toTarget(e: E, rp: E2) = new Tu2Ex[T,T2](e,rp) + def toTarget(e: E, rp: E2) = new Tu2Ex[T,T2](e, rp) }} implicit def tuple2ToTuple3[T1,E1 <: Ex[T1],T2,E2 <: Ex[T2],T3,E3 <: RP[T3]] = { @@ -96,6 +106,16 @@ object ExprToTarget { def toTarget(e: Tu2Ex[T1,T2], rp: E3) = new Tu3Ex[T1,T2,T3](e(0), e(1), rp) }} + implicit def tuple3ToTuple4[T1,E1 <: Ex[T1],T2,E2 <: Ex[T2],T3,E3 <: Ex[T3],T4,E4 <: RP[T4]] = { + new ExprToTarget[(T1,T2,T3),Tu3Ex[T1,T2,T3],T4,E4,(T1,T2,T3,T4),Tu4Ex[T1,T2,T3,T4]]() { + def toTarget(e: Tu3Ex[T1,T2,T3], rp: E4) = new Tu4Ex[T1,T2,T3,T4](e(0), e(1), e(2), rp) + }} + + implicit def tuple4ToTuple5[T1,E1 <: Ex[T1],T2,E2 <: Ex[T2],T3,E3 <: Ex[T3],T4,E4 <: Ex[T4],T5,E5 <: RP[T5]] = { + new ExprToTarget[(T1,T2,T3,T4),Tu4Ex[T1,T2,T3,T4],T5,E5,(T1,T2,T3,T4,T5),Tu5Ex[T1,T2,T3,T4,T5]]() { + def toTarget(e: Tu4Ex[T1,T2,T3,T4], rp: E5) = new Tu5Ex[T1,T2,T3,T4,T5](e(0), e(1), e(2), e(3), rp) + }} + } // combine E1 and E2 into E3 diff --git a/querydsl-scala/src/main/scala/com/mysema/scala/ManifestUtils.scala b/querydsl-scala/src/main/scala/com/mysema/scala/ManifestUtils.scala new file mode 100644 index 000000000..58b04509e --- /dev/null +++ b/querydsl-scala/src/main/scala/com/mysema/scala/ManifestUtils.scala @@ -0,0 +1,11 @@ +package com.mysema.scala + +/** + * @author tiwe + * + */ +object ManifestUtils { + + implicit def toClass[X](mf: Manifest[X]) = mf.erasure.asInstanceOf[Class[X]] + +} \ No newline at end of file diff --git a/querydsl-scala/src/main/scala/com/mysema/scala/ReflectionUtils.scala b/querydsl-scala/src/main/scala/com/mysema/scala/ReflectionUtils.scala new file mode 100644 index 000000000..74de048d4 --- /dev/null +++ b/querydsl-scala/src/main/scala/com/mysema/scala/ReflectionUtils.scala @@ -0,0 +1,31 @@ +package com.mysema.scala; + +import java.lang.reflect._ +import javax.annotation.Nullable; +import scala.collection.mutable.ListBuffer + +/** + * @author tiwe + * + */ +object ReflectionUtils { + + def getSuperClasses(cl: Class[_]): List[Class[_]] = { + if (cl != null) Nil else cl :: getSuperClasses(cl.getSuperclass) + } + + def getFields(cl: Class[_]): List[Field] = { + getSuperClasses(cl).flatMap(_.getDeclaredFields) + } + + def getImplementedInterfaces(cl: Class[_]): Set[Class[_]] = { + getSuperClasses(cl).flatMap(_.getInterfaces).toSet + } + + def getNameAndValue[T](o: AnyRef, field: Field): (String,T) = { + field.setAccessible(true) + val v = field.get(o).asInstanceOf[T] + (field.getName, v) + } + +} diff --git a/querydsl-scala/src/test/scala/com/mysema/query/scala/QPerson.scala b/querydsl-scala/src/test/scala/com/mysema/query/scala/QPerson.scala index 8f7d545d4..98a351b89 100644 --- a/querydsl-scala/src/test/scala/com/mysema/query/scala/QPerson.scala +++ b/querydsl-scala/src/test/scala/com/mysema/query/scala/QPerson.scala @@ -19,30 +19,30 @@ class QPerson(cl: Class[_ <: Person], md: PathMetadata[_]) extends EntityPathImp lazy val other = new QPerson(this, "other") - val array = createArray("array", classOf[Array[String]]) + val array = createArray[Array[String]]("array") val firstName = createString("firstName") - val javaCollection = createCollection("javaCollection", classOf[String], classOf[StringPath]) + val javaCollection = createCollection[String,StringPath]("javaCollection") - val javaDouble = createNumber("javaDouble", classOf[java.lang.Double]) + val javaDouble = createNumber[java.lang.Double]("javaDouble") - val javaInt = createNumber("javaInt", classOf[Integer]) + val javaInt = createNumber[Integer]("javaInt") - val javaList = createList("javaList", classOf[String], classOf[StringPath]) + val javaList = createList[String,StringPath]("javaList") - val javaMap = createMap("javaMap", classOf[String], classOf[String], classOf[StringPath]) + val javaMap = createMap[String,String,StringPath]("javaMap") - val javaSet = createSet("javaSet", classOf[String], classOf[StringPath]) + val javaSet = createSet[String,StringPath]("javaSet") val lastName = createString("lastName") - val listOfPersons = createList("listOfPersons", classOf[Person], classOf[QPerson]) + val listOfPersons = createList[Person,QPerson]("listOfPersons") - val scalaInt = createNumber("scalaInt", classOf[Integer]) + val scalaInt = createNumber[Integer]("scalaInt") - val scalaList = createList("scalaList", classOf[String], classOf[StringPath]) + val scalaList = createList[String,StringPath]("scalaList") - val scalaMap = createMap("scalaMap", classOf[String], classOf[String], classOf[StringPath]) + val scalaMap = createMap[String,String,StringPath]("scalaMap") } \ No newline at end of file diff --git a/querydsl-scala/src/test/scala/com/mysema/query/scala/QPersonTest.scala b/querydsl-scala/src/test/scala/com/mysema/query/scala/QPersonTest.scala index 4e3911f20..02a62ce2e 100644 --- a/querydsl-scala/src/test/scala/com/mysema/query/scala/QPersonTest.scala +++ b/querydsl-scala/src/test/scala/com/mysema/query/scala/QPersonTest.scala @@ -9,7 +9,7 @@ import Matchers._ class QPersonTest { val person = QPerson as "person" - + @Test def EntityPath { assertEquals("person.other.firstName", person.other.firstName) diff --git a/querydsl-scala/src/test/scala/com/mysema/query/scala/sql/PathsTest.scala b/querydsl-scala/src/test/scala/com/mysema/query/scala/sql/PathsTest.scala new file mode 100644 index 000000000..9904ca679 --- /dev/null +++ b/querydsl-scala/src/test/scala/com/mysema/query/scala/sql/PathsTest.scala @@ -0,0 +1,17 @@ +package com.mysema.query.scala.sql + +import org.junit._ +import org.junit.Assert._ +import com.mysema.query.sql._ +import com.mysema.query.types._ +import test._ + +class PathsTest { + + @Test + def Projection { + val projection = Employee.getProjection.asInstanceOf[FactoryExpression[_]] + assertEquals(4, projection.getArgs.size) + } + +} \ No newline at end of file diff --git a/querydsl-scala/src/test/scala/com/mysema/query/scala/sql/QueriesTest.scala b/querydsl-scala/src/test/scala/com/mysema/query/scala/sql/QueriesTest.scala index 022e44c36..0b9a49e66 100644 --- a/querydsl-scala/src/test/scala/com/mysema/query/scala/sql/QueriesTest.scala +++ b/querydsl-scala/src/test/scala/com/mysema/query/scala/sql/QueriesTest.scala @@ -3,6 +3,7 @@ package com.mysema.query.scala.sql import org.junit._ import org.junit.Assert._ import com.mysema.query.sql._ +import com.mysema.query.types._ import java.sql.Connection import test._ @@ -12,7 +13,7 @@ class QueriesTest extends SQLHelpers { val templates = new H2Templates() def connection: Connection = null - + @Test def From { assertEquals("from EMPLOYEE employee", Employee.query.toString) diff --git a/querydsl-scala/src/test/scala/test/QEmployee.scala b/querydsl-scala/src/test/scala/test/QEmployee.scala index 1d3b8a7d3..ec2d10296 100644 --- a/querydsl-scala/src/test/scala/test/QEmployee.scala +++ b/querydsl-scala/src/test/scala/test/QEmployee.scala @@ -21,11 +21,11 @@ class QEmployee(md: PathMetadata[_]) extends RelationalPathImpl[Employee](md, "P val firstname = createString("FIRSTNAME") - val id = createNumber("ID", classOf[Integer]) + val id = createNumber[Integer]("ID") val lastname = createString("LASTNAME") - val superiorId = createNumber("SUPERIOR_ID", classOf[Integer]) + val superiorId = createNumber[Integer]("SUPERIOR_ID") val sysIdx55: PrimaryKey[Employee] = createPrimaryKey(id); diff --git a/querydsl-scala/src/test/scala/test/QSurvey.scala b/querydsl-scala/src/test/scala/test/QSurvey.scala index 74068bebd..d554895e9 100644 --- a/querydsl-scala/src/test/scala/test/QSurvey.scala +++ b/querydsl-scala/src/test/scala/test/QSurvey.scala @@ -18,7 +18,7 @@ class QSurvey(md: PathMetadata[_]) extends RelationalPathImpl[Survey](md, "PUBLI def this(parent: Path[_], variable: String) = this(forProperty(parent, variable)) - val id = createNumber("ID", classOf[Integer]) + val id = createNumber[Integer]("ID") val name = createString("NAME")