Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Slick: Bringing Scala’s Powerful Features to Your Database Access

4,162 views

Published on

This talk will teach you how to use Slick in practice, based on our experience at EatingWell Media Group. Slick is a totally different (and better!) relational database mapping tool that brings Scala’s powerful features to your database interactions, namely: static-checking, compile-time safety, and compositionality.

Here at EatingWell, we have learned quite a bit about Slick over the past two years as we transitioned from a PHP website to Scala. I will share with you tips and tricks we have learned, as well as everything you need to get started using Slick in your Scala application.

I will begin with Slick fundamentals: how to get started making your connection, the types of databases it can access, how to actually create table objects and make queries to and from them. We will using these fundamentals to demonstrate the powerful features inherited from the Scala language itself: static-checking, compile-time safety, and compositionality. And throughout I will share plenty of tips that will help you in everything from getting started to connection pooling options and configuration for use at scale.

Published in: Technology

Slick: Bringing Scala’s Powerful Features to Your Database Access

  1. 1. The Slick Library Rebecca Grenier rebeccagrenier@gmail.com
  2. 2. Intro to Slick  Static Typing + Compilation = Type Safety  For-Comprehensions  Compositionality: build complex queries out of simple parts @beckythebest
  3. 3. Introduction to Slick @beckythebest
  4. 4. Slick Connection Drivers  Oracle ($$$)  DB2 ($$$)  SQL Server ($$$) @beckythebest Note: Connection Pooling is your responsibility  PostgreSQL  MySQL  Access  Derby  H2  Hsqldb  SQLite
  5. 5. The Files Table @beckythebest Field Type Null id int (10) unsigned NO uid int (10) unsigned NO path varchar (255) NO filetype varchar (255) NO
  6. 6. Table Definitions: Mapping to tuples @beckythebest
  7. 7. Table Definitions: Mapping to case classes @beckythebest
  8. 8. How the 22-item tuple Limit Affects Slick What if your table has more than 22 columns? Define multiple Table Classes that refer to the same table – similar to “views” * There is a workaround for Scala >= 2.10.3 where you can use HList instead @beckythebest
  9. 9. Queries in Slick Every query starts out as a TableQuery first: val files = TableQuery[Files] is the equivalent of select * from files; (You can use .selectStatement on any query to see the SQL for a select statment that is generated behind the scenes) @beckythebest
  10. 10. A Quick Full Example val allFiles = db withSession { implicit session => files.run } allFiles is a Vector of File case class objects files is just the query and remains so until it is invoked (with .run) @beckythebest
  11. 11. Building Your Query: Adding a Where Clause With .filter files.filter(_.filetype === ‘pdf’) In SQL: select * from files where filetype= ’pdf’ • In Slick, equals is === • Not-Equals is =!= @beckythebest
  12. 12. Use Method Chaining to Add More Clauses to Your Query Slick: files.filter(_.filetype === “pdf”).filter(_.id < 20000) SQL: select * from files where filetype= “pdf” and id < 20000 Reminder: You are not really filtering yet; @beckythebest you are building a Query.
  13. 13. Query Building with Modifiers from Slick’s DSL  take files.take(5) SQL: select * from files limit 5  Drop files.drop(5) SQL: select * from files offset 5  length files.length SQL: select count(*) from files  map  flatMap  sortBy SQL: sort by @beckythebest
  14. 14. Connecting to Your Database in Slick Connect with Database.forURL There is also forDriver, forName, and forDataSource @beckythebest
  15. 15. Queries Need Sessions Use that Database Connection to get a Session @beckythebest This is a static session
  16. 16. Just Say No to Dynamic Sessions AKA A non-explicit session you hope was opened earlier this thread Dynamic Sessions You can’t count on your thread having a session in an @beckythebest asyncronous world
  17. 17. Query Invokers Invoker Returns Vector of results List of results First result or Exception Some(first) or None Nothing files.run files.list files.first files.firstOption files.execute @beckythebest
  18. 18. Invoke a Delete Query scala> files.deleteStatement res5: String = delete from `files` invoke with .delete files.delete @beckythebest
  19. 19. Just Delete One Record Reduce your query with filter: > files.filter(_.id === 56).deleteStatement res6: String = delete from `files` where `files`.`id` = 56 Invoked: files.filter(_.id === 56).delete @beckythebest
  20. 20. Insert Query Invoker scala> files.insertStatement res1: String = insert into `files` (`id`,`path`,`filetype`,`uid`) values (?,?,?,?) invoke with += files += File(0, “path to file”, “type”, 333) @beckythebest
  21. 21. Update Query Invoker scala> files.map(_.path).updateStatement res4: String = update `files` set `path` = ? invoke with .update() files.map(_.path).update(“new path to file”) @beckythebest
  22. 22. Best Practice: Build your Query Completely BEFORE Invoking The commands below look similar but have very different performance: files.take(5).run SQL: (select * from files limit 5) files.run.take(5) SQL: (select * from files) take 5 @beckythebest
  23. 23. What good is all this Typing? Use SQL to query the files table by fid (which is an integer) What happens when a non-integer value gets passed in? @beckythebest No error? No big deal!
  24. 24. VS. Static Typing If you do the same thing in Slick: We get the following error at compile time: @beckythebest
  25. 25. Joining: Introducing The Users Table @beckythebest
  26. 26. Files has a new column: uid @beckythebest
  27. 27. Joining with For- Comprehensions SQL: select * from users,files where files.uid = users.id When invoked (with innerJoinFileUser.run) this returns a Collection of tuples with the first item being of type User and the second being of type File @beckythebest
  28. 28. Where Clauses in For- Comprehensions  Use filter expressions instead of filters  Example: limit to only files owned by Sarah: @beckythebest
  29. 29. Slick also has its own Join Methods We just looked at this query joined with a for-comprehension: Same query joined with innerJoin method: @beckythebest
  30. 30. The SQL Behind the Scenes Joined with a for-comprehension select x2.`uid`, x2.`name`, x2.`mail`, x2.`status`, x3.`id`, x3.`path`, x3.`filetype`, x3.`uid` from `users` x2, `files` x3 where x3.`id` = x2.`uid` Joined with the innerJoin method select x2.x3, x2.x4, x2.x5, x2.x6, x7.x8, x7.x9, x7.x10, x7.x11 from (select x12.`id` as x3, x12.`name` as x4, x12.`mail` as x5, x12.`status` as x6 from `users` x12) x2 inner join (select x13.`id` as x8, x13.`path` as x9, x13.`filetype` as x10, x13.`uid` as x11 from `files` x13) x7 on x2.x3 = x7.x11 @beckythebest
  31. 31. Return Anything You Want With these for-comprehension use yield to reduce the data you want returned Instead of yield(u, f) you could have  yield(f)  yield (u.name, f.path)  yield (f.path) @beckythebest
  32. 32. Slick Outer Joins  You can’t do these with for-comprehensions  f.path.? turns values into Options (there might not be files for every user)  f.? doesn’t work * Remember, you can always use plain SQL with Slick @beckythebest
  33. 33. Query Compositionality Every query does Double Duty: 1. Invoke to get data 2. Use as a building block for another query @beckythebest
  34. 34. Create Query Methods object Files { def byType(filetype: String) = files.filter(_.filetype === filetype) } implicit session => Files.byType(“text/html”).list Returns a list of HTML File case classes @beckythebest
  35. 35. Let’s Look at the SQL Behind That The method itself is not a Query, but it returns a Query scala> filesByType.selectStatement ERROR scala> filesByType(“pdf").selectStatement res3: String = select * from `files` x2 where x2.`filetype` = ‘pdf' @beckythebest
  36. 36. Composing Queries out of Queries object Users { def userPDFS(email: String) = for { u <- users if u.email === email f <- Files.byType(“pdf”) if f.uid === u.id } yield (f) } @beckythebest
  37. 37. Quick Look at the SQL scala> userPDFS("sarah@eatingwell.com").selectStatement res0: String = select files`id`, files.`path`, files.`filetype`, files.`id` from `users`, `files` where ((users.`mail` = 'sarah@eatingwell.com') and (files.`filetype` = 'application/pdf')) and (files.`uid` = users.`id`) * There are many more advanced ways @beckythebest
  38. 38. Use the Combos in Code Now to get all Sarah’s PDFS is a short, clear statement: val sarahsPdfs = db withSession { implicit session => Users.userPDFS(“sarah@eatingwell.com”).list } sarahsPDFS is now a List of File case classes OR continue to build on it further @beckythebest
  39. 39. Slick Drawbacks Not a lot of documentation for advanced use Re-using Slicks collection methods for query building can be confusing Learning curve (compared to already knowing SQL) (If you do) Not the most efficient SQL @beckythebest
  40. 40. Save Yourselves! There is now code generation in Slick! You don’t have to write out 65 Table class definitions like I did @beckythebest
  41. 41. Summary Slick uses Scala’s best features to bring type safety and composability to your Relational Database access • Static Typing • Collection Methods • For-Comprehensions • Compositionality @beckythebest
  42. 42. Resources Slick Documentation: http://slick.typesafe.com/doc/2.1.0/ Activator’s Hello Slick! http://typesafe.com/activator/template/hello-slick Adam Mackler’s Learning Slick V2 https://mackler.org/LearningSlick2/ IRC chat room #scala on Freenode Advanced Query Composing: http://slick.typesafe.com/talks/2013-12-03_Scala-eXchange/ 2013-12-03_Patterns-for-Slick-database-applications- Scala-eXchange.pdf Working around the 22 tuple limit: http://stackoverflow.com/questions/20555304/how-can-i-use-the- new-slick-2-0-hlist-to-overcome-22-column-limit @beckythebest
  43. 43. Thank You Questions? Rebecca Grenier rebeccagrenier@gmail.com @beckythebest Special Thanks to: Underscore Consulting @beckythebest

×