slick: bringing scala’s powerful features to your database access

43
The Slick Library Rebecca Grenier rebeccagrenier@gmail . com

Upload: rebecca-grenier

Post on 12-Jul-2015

1.129 views

Category:

Technology


2 download

TRANSCRIPT

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

The Slick Library

Rebecca Grenier

[email protected]

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

Intro to Slick

Static Typing + Compilation = Type Safety

For-Comprehensions

Compositionality: build complex queries out of simple

parts

@beckythebest

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

Introduction to Slick

@beckythebest

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

Slick Connection Drivers

Oracle ($$$)

DB2 ($$$)

SQL Server ($$$)

@beckythebest

Note: Connection Pooling is your

responsibility

PostgreSQL

MySQL

Access

Derby

H2

Hsqldb

SQLite

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

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

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

Table Definitions:

Mapping to tuples

@beckythebest

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

Table Definitions:

Mapping to case classes

@beckythebest

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

How the 22-item

tuple Limit Affects SlickWhat 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

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

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)

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

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

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

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

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

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.

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

Query Building

with Modifiers from Slick’s DSL

take

files.take(5) SQL: select * from files limit 5

Dropfiles.drop(5) SQL: select * from files offset 5

length

files.length SQL: select count(*) from files

map

flatMap

sortBy SQL: sort by

@beckythebest

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

Connecting to Your Database

in Slick

@beckythebest

Connect with Database.forURL

There is also forDriver, forName, and forDataSource

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

Queries Need Sessions

Use that Database Connection to get a

Session

@beckythebest

This is a static

session

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

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

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

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

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

Invoke a Delete Query

scala> files.deleteStatement

res5: String = delete from `files`

invoke with .delete

files.delete

@beckythebest

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

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

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

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

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

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

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

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

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

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?

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

VS. Static Typing

@beckythebest

We get the following error at compile time:

If you do the same thing in Slick:

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

Joining: Introducing The Users

Table

@beckythebest

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

Files has a new column: uid

@beckythebest

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

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

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

Where Clauses in For-

Comprehensions

Use filter expressions instead of filters

Example: limit to only files owned by Sarah:

@beckythebest

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

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:

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

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

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

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)

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

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

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

Query Compositionality

@beckythebest

Every query does Double

Duty:

1. Invoke to get data

2. Use as a building block for

another query

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

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

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

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

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

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

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

Quick Look at the SQL

scala> 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`)

@beckythebest

* There are many more advanced ways

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

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(“[email protected]”).list

}

sarahsPDFS is now a List of File case classes OR

continue to build on it further

@beckythebest

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

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

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

Save Yourselves!

There is now code generation in Slick!

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

@beckythebest

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

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

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

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

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

Thank You

Questions?

Rebecca Grenier

[email protected]

@beckythebest

Special Thanks to: Underscore Consulting

@beckythebest