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!