Slick: How does autoInc work in the MultiDBCakeExample?

I am trying to understand how Slick works and how to use it ... and looking at their examples on GitHub. I ended this piece of code in MultiDBCakeExample.scala :

trait PictureComponent { this: Profile => //requires a Profile to be mixed in... import profile.simple._ //...to be able import profile.simple._ object Pictures extends Table[(String, Option[Int])]("PICTURES") { ... def * = url ~ id val autoInc = url returning id into { case (url, id) => Picture(url, id) } def insert(picture: Picture)(implicit session: Session): Picture = { autoInc.insert(picture.url) } } } 

I believe that the * method returns a row in the table, and autoInc should somehow provide functionality for automatically increasing the identifier of an object ... but, to be honest, I am a little at a loss in understanding this part of the code. What does returning ? What returns autoInc ?

I looked at the Slick documentation, but I could not find any useful information. Any help would be really appreciated -)

+4
source share
1 answer

Due to the fact that autoInc can be confusing, I will give you a working example (note that my database is PostgreSQL, so I need this hack with forInsert to force Postgresql drivers to increase auto-inc values).

 case class GeoLocation(id: Option[Int], latitude: Double, longitude: Double, altitude: Double) /** * Define table "geo_location". */ object GeoLocations extends RichTable[GeoLocation]("geo_location") { def latitude = column[Double]("latitude") def longitude = column[Double]("longitude") def altitude = column[Double]("altitude") def * = id.? ~ latitude ~ longitude ~ altitude <> (GeoLocation, GeoLocation.unapply _) def forInsert = latitude ~ longitude ~ altitude <> ({ (lat, long, alt) => GeoLocation(None, lat, long, alt) }, { g: GeoLocation => Some((g.latitude, g.longitude, g.altitude)) }) } 

My RichTable is an abstract class so as not to declare identifiers for each table, but I am simply extending this:

 abstract class RichTable[T](name: String) extends Table[T](name) { def id = column[Int]("id", O.PrimaryKey, O.AutoInc) val byId = createFinderBy(_.id) } 

and use it like:

 GeoLocations.forInsert.insert(GeoLocation(None, 22.23, 25.36, 22.22)) 

Since you are passing None for id , it will be automatically generated by the PostgreSql driver when Slick inserts this new object. I have had a few weeks since I started with Slick, and I really recommend it!

UPDATE . If you do not want to use forInsert projections, then another approach is as follows: in my case, the Address object.

Create a sequence for each table when creating the schema:

 session.withTransaction { DBSchema.tables.drop DBSchema.tables.create // Create schemas to generate ids too. Q.updateNA("create sequence address_seq") } 

Define a method for creating identifiers using sequences (I defined this class once in RichTable :

  def getNextId(seqName: String) = Database { implicit db: Session => Some((Q[Int] + "select nextval('" + seqName + "_seq') ").first) } 

and in the insert mapping override method, for example:

  def insert(model : Address) = Database { implicit db: Session => *.insert(model.copy(id = getNextId(classOf[Address].getSimpleName()))) } 

And now you can pass None when you insert, and these methods will do you a nice job ...

+6
source

All Articles