Skip to content

Instantly share code, notes, and snippets.

@laser
Forked from cvogt/gist:9239494
Last active September 15, 2015 03:03

Revisions

  1. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -45,7 +45,6 @@ object RecordsDAO{
    // db.withSession{ implicit session => Records.DAO.foos }
    def foos(implicit s:Session) = records.foos.run
    val byIdCompiled = Compiled(records.byId)
    // or
    def byId(id: Long)(implicit s:Session) = byIdCompiled(id).run.headOption
    ...
    }
  2. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -44,9 +44,9 @@ object RecordsDAO{
    // or
    // db.withSession{ implicit session => Records.DAO.foos }
    def foos(implicit s:Session) = records.foos.run
    val byId = Compiled(records.byId)
    val byIdCompiled = Compiled(records.byId)
    // or
    def byId(id: Long)(implicit s:Session) = records.byId(id).firstOption
    def byId(id: Long)(implicit s:Session) = byIdCompiled(id).run.headOption
    ...
    }
    // usage:
  3. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -44,8 +44,9 @@ object RecordsDAO{
    // or
    // db.withSession{ implicit session => Records.DAO.foos }
    def foos(implicit s:Session) = records.foos.run
    val byIdCompiled = Compiled(records.byId)
    def byId(implicit s:Session) = records.byId(_).firstOption
    val byId = Compiled(records.byId)
    // or
    def byId(id: Long)(implicit s:Session) = records.byId(id).firstOption
    ...
    }
    // usage:
  4. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -45,7 +45,7 @@ object RecordsDAO{
    // db.withSession{ implicit session => Records.DAO.foos }
    def foos(implicit s:Session) = records.foos.run
    val byIdCompiled = Compiled(records.byId)
    def byId = byIdCompiled(_).firstOption
    def byId(implicit s:Session) = records.byId(_).firstOption
    ...
    }
    // usage:
  5. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -30,7 +30,7 @@ implicit class RecordQueryExtensions(val q: Query[Records,Record]) extends AnyVa
    // Methods placed here can be chained/combined.
    ...
    def foos = q.map(_.foo)
    def byId(id: Column[Long]) = f.filter(_.id === id)
    def byId(id: Column[Long]) = q.filter(_.id === id)
    }
    // usage:
    db.withSession{ records.filter(_.age < 30).foos.run }
  6. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -44,6 +44,8 @@ object RecordsDAO{
    // or
    // db.withSession{ implicit session => Records.DAO.foos }
    def foos(implicit s:Session) = records.foos.run
    val byIdCompiled = Compiled(records.byId)
    def byId = byIdCompiled(_).firstOption
    ...
    }
    // usage:
    @@ -55,8 +57,6 @@ db.withSession{ implicit session => Records.DAO.foos }
    case class RecordsDAO(implicit s:Session){
    // centralized implicit session into class argument
    def foos = records.foos.run
    val byIdCompiled = Compiled(records.byId)
    def byId = byIdCompiled(_).firstOption
    ...
    }
    // usage:
  7. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,8 @@ db.withSession{ implicit session => Records.DAO.foos }
    case class RecordsDAO(implicit s:Session){
    // centralized implicit session into class argument
    def foos = records.foos.run
    def byId = Compiled(records.byId)(_).firstOption
    val byIdCompiled = Compiled(records.byId)
    def byId = byIdCompiled(_).firstOption
    ...
    }
    // usage:
  8. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,7 @@ db.withSession{ implicit session => Records.DAO.foos }
    case class RecordsDAO(implicit s:Session){
    // centralized implicit session into class argument
    def foos = records.foos.run
    def byId(id: Long) = Compiled( records.byId )
    def byId = Compiled(records.byId)(_).firstOption
    ...
    }
    // usage:
  9. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -30,6 +30,7 @@ implicit class RecordQueryExtensions(val q: Query[Records,Record]) extends AnyVa
    // Methods placed here can be chained/combined.
    ...
    def foos = q.map(_.foo)
    def byId(id: Column[Long]) = f.filter(_.id === id)
    }
    // usage:
    db.withSession{ records.filter(_.age < 30).foos.run }
    @@ -54,6 +55,7 @@ db.withSession{ implicit session => Records.DAO.foos }
    case class RecordsDAO(implicit s:Session){
    // centralized implicit session into class argument
    def foos = records.foos.run
    def byId(id: Long) = Compiled( records.byId )
    ...
    }
    // usage:
  10. @cvogt cvogt revised this gist Feb 27, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ import scala.slick.driver.H2Driver._
    val db = Database.for...(...)

    case class Record( ... )
    class Records extends Table[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
  11. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -15,8 +15,7 @@ class Records extends Table[Record](...){
    }
    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.
    // (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
    ...
    @@ -86,10 +85,11 @@ case class RecordProjection( ... : Column[...], ... : 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(...),...)
    def projection = RecordProjection(column(...),column(...),...) // column types can be inferred
    def * = projection
    }
    val records = TableQuery[Records].map(_.projection)
  12. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -23,6 +23,7 @@ object records extends TableQuery(new Records(_)){
    }
    // 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
  13. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 43 additions and 21 deletions.
    64 changes: 43 additions & 21 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -1,60 +1,80 @@
    // Please comment in case of typos or bugs

    import scala.slick.driver.H2Driver._
    val db = Database.for...(...)

    case class Record( ... )
    class Records extends Table[Record](...){
    ...
    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, e.g. records.map(_.foo)
    // 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,
    // e.g. records.foos
    // 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 }

    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,
    // e.g. records.filter(_.age < 30).foos
    // Methods placed here can be chained/combined.
    ...
    def foos = q.map(_.foo)
    }
    // 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, e.g.
    // db.withSession{ Records.DAO.all } // or
    // db.withSession{ implicit session => Records.DAO.all }
    def foos(implicit s:Session) = records.foos.list
    // 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
    ...
    }

    // usage:
    db.withSession{ RecordsDAO.foos }
    db.withSession{ implicit session => Records.DAO.foos }

    // Alternative DAO implementation:

    trait DAO{
    def db = Database.for...(...)

    case class RecordsDAO(implicit s:Session){
    // centralized implicit session into class argument
    def foos = records.foos.run
    ...
    }
    object RecordsDAOAlternative extends DAO{
    // user code difference:
    // 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
    // e.g. Records.DAO.foos
    def foos = db.withSession{ implicit s => records.foos.run }
    // or:
    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.
    @@ -63,12 +83,14 @@ object RecordsDAOAlternative extends DAO{
    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, e.g. records.map(_.foo)
    def foo = (col1+col2, col3)
    // 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(...),...)
    def * = projection
    }
    val records = TableQuery[Records].map(_.projection)
    // usage:
    db.withSession{ records.map(_.foo).run }
  14. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    // Please comment in case of typos or bugs

    import scala.slick.driver.H2Driver._
    case class Record( ... )
    class Records extends Table[Record](...){
  15. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,6 @@ object RecordsDAO{
    // methods take Session argument, e.g.
    // db.withSession{ Records.DAO.all } // or
    // db.withSession{ implicit session => Records.DAO.all }
    def all(implicit s:Session) = records.list
    def foos(implicit s:Session) = records.foos.list
    ...
    }
  16. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 57 additions and 15 deletions.
    72 changes: 57 additions & 15 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -1,31 +1,73 @@
    import scala.slick.driver.H2Driver._
    case class Record( ... )
    class Records extends Table[Record](...){
    ...
    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
    // records row, e.g. records.map(_.foo)
    def foo = (col1+col2, col3)
    ...
    }
    object records extends TableQuery(new Records(_)){
    // only place methods here which return a not-yet executed query
    // which is based on the WHOLE table. Seldom useful, often
    // better places in RecordQueryExentions in order to be combined with others
    // Only place methods here which return a not-yet executed Query or
    // (individually meaningful) Column.
    // which is based on the WHOLE table,
    // e.g. records.foos
    // Seldom useful, often better placed in RecordQueryExentions
    def foos = this.map(_.foo) // <- can only be used on the whole table
    ...
    }
    implicit class RecordQueryExtensions(q: Query[Records,Record]){
    // only place methods here which return a not-yet executed query
    // which is based on the WHOLE table.
    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,
    // e.g. records.filter(_.age < 30).foos
    ...
    def foos = q.map(_.foo)
    }
    trait DAO{
    def database = Database.forDataSource(DB.getDataSource("default"))
    lazy val profile = H2Driver
    }
    object RecordsDAO extends DAO{
    object RecordsDAO{
    // place methods here that require a database connection
    // i.e. do not compose without executing queries
    def all = database withSession { implicit s => this.list }
    // i.e. do not compose without executing queries, e.g.
    // methods take Session argument, e.g.
    // db.withSession{ Records.DAO.all } // or
    // db.withSession{ implicit session => Records.DAO.all }
    def all(implicit s:Session) = records.list
    def foos(implicit s:Session) = records.foos.list
    ...
    }

    // Alternative DAO implementation:

    trait DAO{
    def db = Database.for...(...)
    }
    object RecordsDAOAlternative extends DAO{
    // user code difference:
    // no withSession boilerplate but no
    // control over foos / transaction management
    // e.g. Records.DAO.foos
    def foos = db.withSession{ implicit s => records.foos.run }
    // or:
    def foos = db.withSession{ records.foos.run }
    // or:
    def foos = db.withSession{ records.foos.list()(_) }
    ...
    }
    }

    // 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, e.g. records.map(_.foo)
    def foo = (col1+col2, col3)
    }
    implicit object RecordShape extends CaseClassShape(RecordProjection.tupled,Record.tupled)
    class Records extends Table[Record](...){
    def projection = RecordProjection(column(...),column(...),...)
    def * = projection
    }
    val records = TableQuery[Records].map(_.projection)
  17. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,6 @@ trait DAO{
    lazy val profile = H2Driver
    }
    object RecordsDAO extends DAO{

    // place methods here that require a database connection
    // i.e. do not compose without executing queries
    def all = database withSession { implicit s => this.list }
  18. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 5 additions and 3 deletions.
    8 changes: 5 additions & 3 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -18,12 +18,14 @@ implicit class RecordQueryExtensions(q: Query[Records,Record]){
    // which is based on the WHOLE table.
    ...
    }
    object RecordsDAO{
    // place methods here that require a database connection
    // i.e. do not compose without executing queries
    trait DAO{
    def database = Database.forDataSource(DB.getDataSource("default"))
    lazy val profile = H2Driver
    }
    object RecordsDAO extends DAO{

    // place methods here that require a database connection
    // i.e. do not compose without executing queries
    def all = database withSession { implicit s => this.list }

    ...
  19. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    case class Record( ... )
    class Records extends Table[Record] ... {
    class Records extends Table[Record](...){
    ...
    def * = ... <> (Record.tupled,Record.unapply)
    // place additional methods here which return values of type Column
  20. @cvogt cvogt revised this gist Feb 26, 2014. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    class Records extends Table ... {
    case class Record( ... )
    class Records extends Table[Record] ... {
    ...
    def * = ...
    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
  21. @cvogt cvogt created this gist Feb 26, 2014.
    29 changes: 29 additions & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    class Records extends Table ... {
    ...
    def * = ...
    // place additional methods here which return values of type Column
    // (compute artificial columns based on other columns) based on a
    // records row
    ...
    }
    object records extends TableQuery(new Records(_)){
    // only place methods here which return a not-yet executed query
    // which is based on the WHOLE table. Seldom useful, often
    // better places in RecordQueryExentions in order to be combined with others
    ...
    }
    implicit class RecordQueryExtensions(q: Query[Records,Record]){
    // only place methods here which return a not-yet executed query
    // which is based on the WHOLE table.
    ...
    }
    object RecordsDAO{
    // place methods here that require a database connection
    // i.e. do not compose without executing queries
    def database = Database.forDataSource(DB.getDataSource("default"))
    lazy val profile = H2Driver

    def all = database withSession { implicit s => this.list }

    ...
    }