2. Intro to Slick
Static Typing + Compilation = Type Safety
For-Comprehensions
Compositionality: build complex queries out of simple
parts
@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
@beckythebest
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)
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. Building Your Query:
Adding a Where Clause
@beckythebest
With .filter
files.filter(_.filetype === ‘pdf’)
In SQL: select * from files where
filetype= ’pdf’
• In Slick, equals is ===
• Not-Equals is =!=
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
@beckythebest
Reminder: You are not really filtering
yet;
you are building a Query.
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. Connecting to Your Database
in Slick
@beckythebest
Connect with Database.forURL
There is also forDriver, forName, and forDataSource
15. Queries Need Sessions
Use that Database Connection to get a
Session
@beckythebest
This is a static
session
16. Just Say No to
@beckythebest
AKA A non-explicit session you hope was opened earlier this
thread
You can’t count on your thread having a session in an
asyncronous world
Dynamic
Sessions
Dynamic Sessions
17. Query Invokers
Vector of results
List of results
First result or Exception
Some(first) or None
Nothing
@beckythebest
files.run
files.list
files.first
files.firstOption
files.execute
Invoker Returns
18. Invoke a Delete Query
scala> files.deleteStatement
res5: String = delete from `files`
invoke with .delete
files.delete
@beckythebest
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. 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: 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. What good is all this
Typing?
@beckythebest
No error?
No big deal!
Use SQL to query the files table by fid (which is an integer)
What happens when a non-integer value gets passed in?
27. Joining with For-
Comprehensions
SQL: select * from
users,files where
files.uid = users.id
@beckythebest
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
28. Where Clauses in For-
Comprehensions
Use filter expressions instead of filters
Example: limit to only files owned by Sarah:
@beckythebest
29. Slick also has its own Join
Methods
We just looked at this query joined with a for-
comprehension:
@beckythebest
Same query joined with innerJoin method:
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. Return Anything You Want
@beckythebest
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)
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
@beckythebest
* Remember, you can always use plain SQL with Slick
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 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. 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. 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`)
@beckythebest
* There are many more advanced ways
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. 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. 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. 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. 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