The document provides an overview of Slick, a database query library for Scala, highlighting features such as query composition, dynamic queries, and boilerplate reduction in Slick 2.0. It discusses various extensions, including auto-incrementing inserts, customizable code generation, outer joins, and dynamic sorting, aimed at simplifying database interactions and promoting reusability of query logic. Key takeaways emphasize a shift in thinking towards code-based query definitions and the importance of maintaining laziness in evaluations.
Query extensions byInterface
trait HasSuppliers{ def supId: Column[Int] }
class Coffees(…)
extends Table... with HasSuppliers {…}
class CofInventory(…) extends Table... with HasSuppliers {…}
implicit class HasSuppliersExtensions[T <: HasSupplier,E]
( val q: Query[T,E] ){
def bySupId(id: Column[Int]): Query[T,E]
= q.filter( _.supId === id )
def withSuppliers
(s: Query[Suppliers,S] = Tables.suppliers)
: Query[(T,Suppliers),(E,S)]
= q.join(s).on(_.supId===_.id)
def suppliers ...
}
// available quantities of coffees
cofInventory.withSuppliers()
.map{ case (i,s) =>
i.quantity.asColumnOf[String] ++ " of " ++ i.cofName ++ " at " ++ s.name
}
12.
Query extensions summary
•Mindshift required!
Think code, not monolithic query strings.
• Stay completely lazy!
Keep Query[…]s as long as you can.
• Re-use!
Write query functions or extensions
methods for shorter, better and DRY code.
Outer join limitationin Slick
suppliers.leftJoin(coffees)
.on(_.id === _.supId)
.run // SlickException: Read NULL value ...
id
name
name
supId
1
Superior Coffee
NULL
NULL
2
Acme, Inc.
Colombian
2
2
Acme, Inc.
French_Roast
2
LEFT JOIN
id
name
name
supId
1
Superior Coffee
Colombian
2
2
Acme, Inc.
French_Roast
2
Generate auto-join conditions2
…
val joins = tables.flatMap( _.foreignKeys.map{ foreignKey =>
import foreignKey._
val fkt = referencingTable.tableClassName
val pkt = referencedTable.tableClassName
val columns = referencingColumns.map(_.name) zip
referencedColumns.map(_.name)
s"implicit def autojoin${name.capitalize} "+
" = (left:${fkt},right:${pkt}) => " +
columns.map{
case (lcol,rcol) =>
"left."+lcol + " === " + "right."+rcol
}.mkString(" && ")
}
29.
Other uses ofSlick code generation
• Glue code (Play, etc.)
• n-n join code
• Migrating databases (warning: types
change)
(generate from MySQL, create in
Postgres)
• Generate repetitive regarding data model
(aka model driven software engineering)
• Generate DDL for external model
30.
Use code generationwisely
• Don’t loose language-level abstraction
• Add your generator and data model to
version control
• Complete but new and therefor
experimental in Slick
Common use casefor web apps
Dynamically decide
• displayed columns
• filter conditions
• sort columns / order
33.
Dynamic column
class Coffees(tag:Tag)
extends Table[CoffeeRow](…){
val name = column[String]("COF_NAME",…)
}
coffees.map(c => c.name)
coffees.map(c =>
c.column[String]("COF_NAME")
)
Be careful about security!