The Slick Library 
Rebecca Grenier 
rebeccagrenier@gmail.com
Intro to Slick 
 Static Typing + Compilation = Type Safety 
 For-Comprehensions 
 Compositionality: build complex queries out of simple 
parts 
@beckythebest
Introduction to Slick 
@beckythebest
Slick Connection Drivers 
 Oracle ($$$) 
 DB2 ($$$) 
 SQL Server ($$$) 
@beckythebest 
Note: Connection Pooling is your 
responsibility 
 PostgreSQL 
 MySQL 
 Access 
 Derby 
 H2 
 Hsqldb 
 SQLite
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
Table Definitions: 
Mapping to tuples 
@beckythebest
Table Definitions: 
Mapping to case classes 
@beckythebest
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
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
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
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
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.
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
Connecting to Your Database 
in Slick 
Connect with Database.forURL 
There is also forDriver, forName, and forDataSource 
@beckythebest
Queries Need Sessions 
Use that Database Connection to get a 
Session 
@beckythebest 
This is a static 
session
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
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
Invoke a Delete Query 
scala> files.deleteStatement 
res5: String = delete from `files` 
invoke with .delete 
files.delete 
@beckythebest
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
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
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
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
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!
VS. Static Typing 
If you do the same thing in Slick: 
We get the following error at compile time: 
@beckythebest
Joining: Introducing The Users 
Table 
@beckythebest
Files has a new column: uid 
@beckythebest
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
Where Clauses in For- 
Comprehensions 
 Use filter expressions instead of filters 
 Example: limit to only files owned by Sarah: 
@beckythebest
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
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
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
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
Query Compositionality 
Every query does Double 
Duty: 
1. Invoke to get data 
2. Use as a building block for 
another query 
@beckythebest
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
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
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
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
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
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
Save Yourselves! 
There is now code generation in Slick! 
You don’t have to write out 65 Table class definitions like I did 
@beckythebest
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
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
Thank You 
Questions? 
Rebecca Grenier 
rebeccagrenier@gmail.com 
@beckythebest 
Special Thanks to: Underscore Consulting 
@beckythebest

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

  • 1.
    The Slick Library Rebecca Grenier rebeccagrenier@gmail.com
  • 2.
    Intro to Slick  Static Typing + Compilation = Type Safety  For-Comprehensions  Compositionality: build complex queries out of simple parts @beckythebest
  • 3.
    Introduction to Slick @beckythebest
  • 4.
    Slick Connection Drivers  Oracle ($$$)  DB2 ($$$)  SQL Server ($$$) @beckythebest Note: Connection Pooling is your responsibility  PostgreSQL  MySQL  Access  Derby  H2  Hsqldb  SQLite
  • 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.
    Table Definitions: Mappingto tuples @beckythebest
  • 7.
    Table Definitions: Mappingto case classes @beckythebest
  • 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.
    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.
    A Quick FullExample 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.
    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.
    Use Method Chainingto 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.
    Query Building withModifiers 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.
    Connecting to YourDatabase in Slick Connect with Database.forURL There is also forDriver, forName, and forDataSource @beckythebest
  • 15.
    Queries Need Sessions Use that Database Connection to get a Session @beckythebest This is a static session
  • 16.
    Just Say Noto 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.
    Query Invokers InvokerReturns 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.
    Invoke a DeleteQuery scala> files.deleteStatement res5: String = delete from `files` invoke with .delete files.delete @beckythebest
  • 19.
    Just Delete OneRecord 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.
    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.
    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.
    Best Practice: Buildyour 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.
    What good isall 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.
    VS. Static Typing If you do the same thing in Slick: We get the following error at compile time: @beckythebest
  • 25.
    Joining: Introducing TheUsers Table @beckythebest
  • 26.
    Files has anew column: uid @beckythebest
  • 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.
    Where Clauses inFor- Comprehensions  Use filter expressions instead of filters  Example: limit to only files owned by Sarah: @beckythebest
  • 29.
    Slick also hasits own Join Methods We just looked at this query joined with a for-comprehension: Same query joined with innerJoin method: @beckythebest
  • 30.
    The SQL Behindthe 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.
    Return Anything YouWant 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.
    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.
    Query Compositionality Everyquery does Double Duty: 1. Invoke to get data 2. Use as a building block for another query @beckythebest
  • 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.
    Let’s Look atthe 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.
    Composing Queries outof 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.
    Quick Look atthe 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.
    Use the Combosin 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.
    Slick Drawbacks Nota 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.
    Save Yourselves! Thereis now code generation in Slick! You don’t have to write out 65 Table class definitions like I did @beckythebest
  • 41.
    Summary Slick usesScala’s best features to bring type safety and composability to your Relational Database access • Static Typing • Collection Methods • For-Comprehensions • Compositionality @beckythebest
  • 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.
    Thank You Questions? Rebecca Grenier rebeccagrenier@gmail.com @beckythebest Special Thanks to: Underscore Consulting @beckythebest

Editor's Notes

  • #5 Should I go over relational databases vs. whatever mongo is
  • #7 I hope you all know what a tuple is