Generic support for Querydsl usage in Scala is available via querydsl-scala module. To add it to your Maven build, use the following snippet :
<dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-scala</artifactId> <version>${querydsl.version}</version> </dependency>
Querydsl for Scala provides an alternative DSL for expression construction. The Scala DSL utilizes language features such as operator overloading, function pointers and implicit imports for enhanced readability and conciseness.
Here is an overview of the main alternatives :
//Standard Alternative expr isNotNull expr is not(null) expr isNull expr is null expr eq "Ben" expr === "Ben" expr ne "Ben" expr !== "Ben" expr append "X" expr + "X" expr isEmpty expr is empty expr isNotEmpoty expr not empty // boolean left and right left && right left or right left || right expr not !expr // comparison expr lt 5 expr < 5 expr loe 5 expr <= 5 expr gt 5 expr > 5 expr goe 5 expr >= 5 expr notBetween(2,6) expr not between (2,6) expr negate -expr // numeric expr add 3 expr + 3 expr subtract 3 expr - 3 expr divide 3 expr / 3 expr multiply 3 expr * 3 expr mod 5 expr % 5 // collection list.get(0) list(0) map.get("X") map("X")
The Querydsl Scala module offers a few implicit conversion to make Querydsl query projections more Scala compatible.
The RichProjectable and RichSimpleProjectable wrappers should be used to enable Scala projections for Querydsl queries. By importing the contents of com.mysema.query.scala.Helpers the needed implicit conversions become available.
For example the following query with the standard API would return a java.util.List of type Object[].
query.from(person).list(person.firstName, person.lastName, person.age)
With the added conversions you can use select instead of list for Scala list typed results, unique instead of uniqueResult for Option typed results and single instead of singleResult for Option typed results.
The previous query could be expressed like this with the implicit conversions:
import com.mysema.query.scala.Helpers._
query.from(person).select(person.firstName, person.lastName, person.age)
In this case the result type would be List[(String,String,Integer)] or in other words List of Tuple3[String,String,Integer].
Like with Querydsl SQL for Java you need to generate Query types to be able to construct your queries. The following code examples show how this is done :
Generation without Bean types :
val directory = new java.io.File("target/jdbcgen1") val namingStrategy = new DefaultNamingStrategy() val exporter = new MetaDataExporter() exporter.setNamePrefix("Q") exporter.setPackageName("com.mysema") exporter.setSchemaPattern("PUBLIC") exporter.setTargetFolder(directory) exporter.setSerializerClass(classOf[ScalaMetaDataSerializer]) exporter.setCreateScalaSources(true) exporter.setTypeMappings(ScalaTypeMappings.create) exporter.export(connection.getMetaData)
Generation with Bean types :
val directory = new java.io.File("target/jdbcgen2") val namingStrategy = new DefaultNamingStrategy() val exporter = new MetaDataExporter() exporter.setNamePrefix("Q") exporter.setPackageName("com.mysema") exporter.setSchemaPattern("PUBLIC") exporter.setTargetFolder(directory) exporter.setSerializerClass(classOf[ScalaMetaDataSerializer]) exporter.setBeanSerializerClass(classOf[ScalaBeanSerializer]) exporter.setCreateScalaSources(true) exporter.setTypeMappings(ScalaTypeMappings.create) exporter.export(connection.getMetaData)
Querydsl Scala provides a compact query syntax for Querydsl SQL. The syntax is inspired by domain oriented query syntaxes like that from the Rogue framework.
The domain oriented queries are implemented as implicit conversions from RelationalPath instances into queries. This functionality can be made available by implementing the com.mysema.query.scala.sql.SQLHelpers trait in your service or DAO classes.
Using this compact syntax you can use your meta model classes as a starting point for queries.
Instead of the following normal syntax
query().from(employee).select(employee.firstName, employee.lastName)
you could use the companion object of Employee or QEmployee and write it like this
Employee.select(_.firstName, _.lastName)
Instead of giving expressions to orderBy, where, select, single and unique you can give functions which take the root expression of the query and return another expression. The expanded form of the previous example would be
Employee.select({ e => e.firstName }, { e => e.lastName })
See the signature of the com.mysema.query.scala.sql.RichSimpleQuery class for details.
Scala sources for SQL metatypes and projections can be generated with querydsl-maven-plugin. Here is an example configuration
<plugin> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-maven-plugin</artifactId> <version>${querydsl.version}</version> <configuration> <jdbcDriver>com.mysql.jdbc.Driver</jdbcDriver> <jdbcUrl>jdbc:mysql://localhost:3306/test</jdbcUrl> <jdbcUser>matko</jdbcUser> <jdbcPassword>matko</jdbcPassword> <packageName>com.example.schema</packageName> <targetFolder>${project.basedir}/src/main/scala</targetFolder> <exportBeans>true</exportBeans> <createScalaSources>true</createScalaSources> </configuration> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.16</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-scala</artifactId> <version>${querydsl.version}</version> </dependency> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala.version}</version> </dependency> </dependencies> </plugin>
The maven goal to execute is querydsl:export.
When querying with other backends the Expression model has to be created manually or alternatively the alias functionality can be used.
Here is a minimal example with JPA/Hibernate :
@Entity class User { @BeanProperty @Id var id: Integer = _; @BeanProperty var userName: String = _; @BeanProperty @ManyToOne var department: Department = _; } @Entity class Department { @BeanProperty @Id var id: Integer = _; @BeanProperty var name: String = _; }
And here are some query examples
import com.mysema.query.jpa.impl.JPAQuery import org.junit.Test class JPAQueryTest { val person = Person as "person" @Test def Various() { // list query from person where (person.firstName like "Rob%") .list person // unique result query from person where (person.firstName like "Rob%") .unique person // long where query from person .where (person.firstName like "Rob%", person.lastName like "An%") .list person // order query from person orderBy (person.firstName asc) list person // not null query from person .where (person.firstName isEmpty, person.lastName isNotNull) .list person } def query() = new JPAQuery(entityManager) }
The main import for Querydsl Scala integration is the following
import com.mysema.query.scala.Conversions._
The factory method for query creation is
def query() = new JPAQuery(entityManager)
In addition to queries you need variables which can be created like this
val person = Person as "person"