Skip to content

Instantly share code, notes, and snippets.

@cvogt
Last active September 9, 2019 01:30
Show Gist options
  • Save cvogt/9239494 to your computer and use it in GitHub Desktop.
Save cvogt/9239494 to your computer and use it in GitHub Desktop.
Slick app architecture cheat sheet
// Please comment in case of typos or bugs
import scala.slick.driver.H2Driver._
val db = Database.for...(...)
case class Record( ... )
class Records(tag: Tag) extends Table[Record](tag,"RECORDS"){
...
def * = ... <> (Record.tupled,Record.unapply)
// place additional methods here which return values of type Column
// (compute artificial columns based on other columns) based on a
// records row
def foo = (col1+col2, col3)
...
}
object records extends TableQuery(new Records(_)){
// Only place methods here which return a not-yet executed Query or
// (individually meaningful) Column which is based on the WHOLE table.
// Seldom useful, often better placed in RecordQueryExentions
def foos = this.map(_.foo) // <- can only be used on the whole table
...
}
// usage:
db.withSession{ records.map(_.foo).run }
db.withSession{ records.foos.run }
implicit class RecordQueryExtensions(val q: Query[Records,Record]) extends AnyVal{
// Only place methods here which return a not-yet executed Query or
// (individually meaningful) Column.
// Methods placed here can be chained/combined.
...
def foos = q.map(_.foo)
def byId(id: Column[Long]) = q.filter(_.id === id)
}
// usage:
db.withSession{ records.filter(_.age < 30).foos.run }
object RecordsDAO{
// place methods here that require a database connection
// i.e. do not compose without executing queries, e.g.
// methods take Session argument
// usage:
// db.withSession{ RecordsDAO.foos }
// or
// db.withSession{ implicit session => Records.DAO.foos }
def foos(implicit s:Session) = records.foos.run
val byIdCompiled = Compiled(records.byId)
def byId(id: Long)(implicit s:Session) = byIdCompiled(id).run.headOption
...
}
// usage:
db.withSession{ RecordsDAO.foos }
db.withSession{ implicit session => Records.DAO.foos }
// Alternative DAO implementation:
case class RecordsDAO(implicit s:Session){
// centralized implicit session into class argument
def foos = records.foos.run
...
}
// usage:
db.withSession{ RecordsDAO().foos }
db.withSession{ implicit session => RecordsDAO().foos }
// Another alternative DAO implementation:
object RecordsDAO{
// in user code
// no withSession boilerplate but no
// control over foos / transaction management
def foos = db.withSession{ records.foos.run }
// or:
def foos = db.withSession{ implicit s => records.foos.run }
// or:
def foos = db.withSession{ records.foos.list()(_) }
...
}
// usage:
RecordsDAO.foos
// Alternative Table class implementation using a mapped projection case class
// Allows projection case classes to be nested and re-used in queries and multiple tables.
// Uses the recently born CaseClassShape suggested here:
// https://github.com/slick/slick/pull/692
case class RecordProjection( ... : Column[...], ... : Column[...], ... ){
// place additional methods here which return values of type Column
// (compute artificial columns based on other columns) based on a
// records row
def foo = (col1+col2, col3)
...
}
implicit object RecordShape extends CaseClassShape(RecordProjection.tupled,Record.tupled)
class Records extends Table[Record](...){
def projection = RecordProjection(column(...),column(...),...) // column types can be inferred
def * = projection
}
val records = TableQuery[Records].map(_.projection)
// usage:
db.withSession{ records.map(_.foo).run }
@octonato
Copy link

The advantage of the slick-dao is that it implements the basic CRUD in a DAO so we don't have to manipulate queries or any infrastructure/DB code in your domain. Nothing more than that.

I do that because I want everything to go through a DAO, basic CRUD and queries. Otherwise the domain gets cluttered with some locally defined queries, some DAOs, extensions and some on.

@asido
Copy link

asido commented May 5, 2015

Typo on lines 19: s/RecordQueryExentions/RecordQueryExtensions/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment