Date post: | 09-Jan-2017 |
Category: |
Software |
Upload: | artem-vlasenko |
View: | 106 times |
Download: | 0 times |
@beckythebest
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 ($$$)
Note: Connection Pooling is your responsibility
PostgreSQL MySQL Access Derby H2 Hsqldb SQLite
@beckythebest
The Files Table
Field Type Null
id int (10) unsigned
NO
uid int (10) unsigned
NO
path varchar (255) NOfiletype varchar (255) NO
@beckythebest
Table Definitions: Mapping to tuples
@beckythebest
Table Definitions:Mapping to case classes
@beckythebest
How the 22-itemtuple 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 SlickEvery 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 objectsfiles 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;
you are building a Query.
@beckythebest
Query Buildingwith 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
lengthfiles.length SQL: select count(*) from files
map flatMap sortBy SQL: sort by
@beckythebest
Connecting to Your Databasein Slick
Connect with Database.forURL
There is also forDriver, forName, and forDataSource
@beckythebest
Queries Need SessionsUse that Database Connection to get a Session
This is a static session
@beckythebest
Just Say No toAKA 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
@beckythebest
Query Invokers
Vector of resultsList of resultsFirst result or ExceptionSome(first) or NoneNothing
files.run
files.list
files.first
files.firstOption files.execute
Invoker Returns
@beckythebest
Invoke a Delete Queryscala> files.deleteStatement
res5: String = delete from `files`
invoke with .delete files.delete
@beckythebest
Just Delete One RecordReduce 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 Invokerscala> 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 Invokerscala> 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?
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?
@beckythebest
VS. Static Typing
We get the following error at compile time:
If you do the same thing in Slick:
@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 returnedInstead 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 CompositionalityEvery query does Double Duty:
1. Invoke to get data
2. Use as a building block for another query
@beckythebest
Create Query Methodsobject 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 Queryscala> 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 SQLscala> userPDFS("[email protected]").selectStatement
res0: String = select files`id`, files.`path`, files.`filetype`, files.`id` from `users`, `files` where ((users.`mail` = '[email protected]') and (files.`filetype` = 'application/pdf')) and (files.`uid` = users.`id`)
* There are many more advanced ways
@beckythebest
Use the Combos in CodeNow to get all Sarah’s PDFS is a short, clear statement:val sarahsPdfs = db withSession {
implicit session =>
Users.userPDFS(“[email protected]”).list
}
sarahsPDFS is now a List of File case classes OR continue to build on it further
@beckythebest
Slick DrawbacksNot a lot of documentation for advanced useRe-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.pdfWorking 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 [email protected]@beckythebestSpecial Thanks to: Underscore Consulting