scala slick-2

43
The Slick Library Rebecca Grenier rebeccagrenier@gmail. com

Upload: artem-vlasenko

Post on 09-Jan-2017

110 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Scala Slick-2

The Slick LibraryRebecca Grenier

[email protected]

Page 2: Scala Slick-2

@beckythebest

Intro to Slick Static Typing + Compilation = Type Safety For-Comprehensions Compositionality: build complex queries out of

simple parts

Page 3: Scala Slick-2

@beckythebest

Introduction to Slick

Page 4: Scala Slick-2

@beckythebest

Slick Connection Drivers Oracle ($$$) DB2 ($$$) SQL Server ($$$)

Note: Connection Pooling is your responsibility

PostgreSQL MySQL Access Derby H2 Hsqldb SQLite

Page 5: Scala Slick-2

@beckythebest

The Files Table

Field Type Null

id int (10) unsigned

NO

uid int (10) unsigned

NO

path varchar (255) NOfiletype varchar (255) NO

Page 6: Scala Slick-2

@beckythebest

Table Definitions: Mapping to tuples

Page 7: Scala Slick-2

@beckythebest

Table Definitions:Mapping to case classes

Page 8: Scala Slick-2

@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

Page 9: Scala Slick-2

@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)

Page 10: Scala Slick-2

@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)

Page 11: Scala Slick-2

@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 =!=

Page 12: Scala Slick-2

@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.

Page 13: Scala Slick-2

@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

Page 14: Scala Slick-2

@beckythebest

Connecting to Your Databasein Slick

Connect with Database.forURL

There is also forDriver, forName, and forDataSource

Page 15: Scala Slick-2

@beckythebest

Queries Need SessionsUse that Database Connection to get a Session

This is a static session

Page 16: Scala Slick-2

@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

Page 17: Scala Slick-2

@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

Page 18: Scala Slick-2

@beckythebest

Invoke a Delete Queryscala> files.deleteStatement

res5: String = delete from `files`

invoke with .delete files.delete

Page 19: Scala Slick-2

@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

Page 20: Scala Slick-2

@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)

Page 21: Scala Slick-2

@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”)

Page 22: Scala Slick-2

@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

Page 23: Scala Slick-2

@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?

Page 24: Scala Slick-2

@beckythebest

VS. Static Typing

We get the following error at compile time:

If you do the same thing in Slick:

Page 25: Scala Slick-2

@beckythebest

Joining: Introducing The Users Table

Page 26: Scala Slick-2

@beckythebest

Files has a new column: uid

Page 27: Scala Slick-2

@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

Page 28: Scala Slick-2

@beckythebest

Where Clauses in For-Comprehensions

Use filter expressions instead of filters Example: limit to only files owned by Sarah:

Page 29: Scala Slick-2

@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:

Page 30: Scala Slick-2

@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

Page 31: Scala Slick-2

@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)

Page 32: Scala Slick-2

@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

Page 33: Scala Slick-2

@beckythebest

Query CompositionalityEvery query does Double Duty:

1. Invoke to get data

2. Use as a building block for another query

Page 34: Scala Slick-2

@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

Page 35: Scala Slick-2

@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'

Page 36: Scala Slick-2

@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)

}

Page 37: Scala Slick-2

@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

Page 38: Scala Slick-2

@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

Page 39: Scala Slick-2

@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

Page 40: Scala Slick-2

@beckythebest

Save Yourselves!There is now code generation in Slick!

You don’t have to write out 65 Table class definitions like I did

Page 41: Scala Slick-2

@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

Page 42: Scala Slick-2

@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

Page 43: Scala Slick-2

@beckythebest

Thank You

Questions?

Rebecca [email protected]@beckythebestSpecial Thanks to: Underscore Consulting