Slick @ Confitura 2013

79
Maciek Próchniak

description

Slick @ Confitura 2013

Transcript of Slick @ Confitura 2013

Page 1: Slick @ Confitura 2013

Maciek Próchniak

Page 2: Slick @ Confitura 2013

Jak udawaćże nie mamybazy danych

Page 3: Slick @ Confitura 2013

Oracle view

Page 4: Slick @ Confitura 2013

DDD/OOP view

Page 5: Slick @ Confitura 2013

Larry

Page 6: Slick @ Confitura 2013

Uncle Bob

Page 7: Slick @ Confitura 2013

Repozytorium?

public interface Repository<T> {

void save(T object);

Collection<T> loadAll();

T load(Id id);

}

Page 8: Slick @ Confitura 2013

Repozytorium?

public interface Repository<Presentation> {

Collection<Presentation>

findByCategoryWithPopularityGreaterThan

(String name, double popularity, int limit);

...

}

Page 9: Slick @ Confitura 2013

Zapytania też mogą być

logiką!

Page 10: Slick @ Confitura 2013

Dashboard

Page 11: Slick @ Confitura 2013

Kolekcje - Java

Collection<Presentation> ret =

new HashSet<Presentation>();

for (Presentation presentation : presentations) {

if (presentation.getPopularity() > popularity) {

for (Author author : authors) {

if (author.getName().equals(name)

&& author.getId()

== presentation.getAuthorId() ) {

ret.add(presentation);

}

}

}

}

return ret;

Page 12: Slick @ Confitura 2013

Techniki

● JDBC

● i(my??)Batis

● Hibernate/JPA

● Hades

● SpringData

● jOOQ

● OneWEBSQL

Page 13: Slick @ Confitura 2013

Object/Relational Mapping is the Vietnam of Computer Science

- Ted Neward

ORM - OMG- Rich Hickey

Page 14: Slick @ Confitura 2013

SQL?

SELECT p.* from PRESENTATIONS p, AUTHORS a where p.authorId = a.id and p.popularity > :popularity and a.name = :name

Page 15: Slick @ Confitura 2013

SQL - kompozycja???

Page 16: Slick @ Confitura 2013

???

Page 17: Slick @ Confitura 2013

.Net

LINQ makes a query a first-class language construct in C# and Visual Basic.

var results = from c in Suppliers where c.size < 1 select new {c.name, c.address};

Page 18: Slick @ Confitura 2013

JVM?

Page 19: Slick @ Confitura 2013

map

Page 20: Slick @ Confitura 2013

tasks

:List[Task]

convert:Task->View

Page 21: Slick @ Confitura 2013

tasks.map(convert) : List[View]

Page 22: Slick @ Confitura 2013

flatMap

Page 23: Slick @ Confitura 2013

tasks:List[Task]

createSubtasks:Task->List[Task]

Page 24: Slick @ Confitura 2013

tasks.flatMap(createSubtasks):List[Task]

Page 25: Slick @ Confitura 2013

Kolekcje - Scala!

presentations.flatMap(presentation =>

authors

.filter(author =>

author.id == presentation.authorId)

.filter(author => author.name == name

&& presentation.popularity > popularity)

.map(_ => presentation)

)

Page 26: Slick @ Confitura 2013

Kolekcje - Scala!

for {

presentation <- presentations

author <- authors

if (author.id == presentation.authorId)

if (author.name == name &&

presentation.popularity > popularity)

} yield presentation

Page 27: Slick @ Confitura 2013

SQL - Scala

SELECT p.* from PRESENTATIONS p

for {p <- presentations

} yield p

Page 28: Slick @ Confitura 2013

Filtrowanie

SELECT p.* from PRESENTATIONS pWHERE p.rank > 5

for {p <- presentationsif p.rank > 5

} yield p

Page 29: Slick @ Confitura 2013

Projekcja

SELECT p.name from PRESENTATIONS pWHERE p.rank > 5

for {p <- presentationsif p.rank > 5

} yield p.name

Page 30: Slick @ Confitura 2013

Join

SELECT p.name,a.name from PRESENTATIONS p, AUTHORS a WHERE

p.authorId = a.id

for { p <- presentations a <- authors if

(p.authorId==a.id)} yield (p.name,a.name)

Page 31: Slick @ Confitura 2013

InnerJoin

SELECT p.name,a.name from PRESENTATIONS p, INNER JOIN AUTHORS a ON

p.authorId = a.id

for { p <- presentations a <-

authors(p.authorId)} yield (p.name,a.name)

Page 32: Slick @ Confitura 2013

Order by, limit

SELECT p.* from PRESENTATIONS porder by p.namelimit 10

(for {p <- presentations

} yield p).sortBy(_.name).take(10)

Page 33: Slick @ Confitura 2013

Deklaratywność w Scali

tasks

.map(_.name)

.filter(_.priority > 4)

.take(3)

Page 34: Slick @ Confitura 2013

● Statyczne typowanie

● Deklaratywność

● Predykaty = wyrażenia Scali

● Standardowe API - (flat)Map

Page 35: Slick @ Confitura 2013

Logika DAO DB

findByNameOrderByTypefindByTypeGroupByCategory

...

Page 36: Slick @ Confitura 2013

Logika DAO DB

query

Page 37: Slick @ Confitura 2013

???

Page 38: Slick @ Confitura 2013

Scala

Language

Integrated

Connectivity

Kit

Page 39: Slick @ Confitura 2013

Play!

Akka

Slick

Scala

Typesafe

Page 40: Slick @ Confitura 2013

Slick

● Obsługa różnych baz

● Łatwa konfiguracja

● DML

● Ochrona przed SQL injection

● bla

● bla

● bla

Page 41: Slick @ Confitura 2013
Page 42: Slick @ Confitura 2013

zapytania ~

operacje na kolekcjachScali

Page 43: Slick @ Confitura 2013

SLICK - architektura

AST

H2MySQL

Lifted

Page 44: Slick @ Confitura 2013

Lifted - predykaty

for {

speaker <- Query(Speakers)

if (speaker.name startsWith "Maciek")

} yield (speaker.twitter)

Page 45: Slick @ Confitura 2013

Lifted - metadane

object Speakers extends Table[Speaker]("speakers") {

def id = column[Long]("id")

def name = column[String]("name")

def twitter = column[TwitterId]("twitterId")

def * = id ~ name ~ twitter <> (

Speaker.apply _, Speaker.unapply _)

}

Page 46: Slick @ Confitura 2013

Lifted - predykaty

for {

speaker <- Query(Speakers)

if (speaker.name startsWith "Maciek")

} yield (speaker.twitter)

Page 47: Slick @ Confitura 2013

abstract class Query[+E, U] {

def flatMap[F, T](f: E => Query[F, T]): Query[F, T] = ...

def map[F, G, T](f: E => F)

(implicit shape: Shape[F, T, G]): Query[G, T] = ...

def filter[T](f: E => T)

(implicit wt: CanBeQueryCondition[T]): Query[E, U]

}

Page 48: Slick @ Confitura 2013

trait UnitInvoker[+R] extends Invoker[Unit, R] {

final def list()(implicit session: JdbcBackend#Session): List[R]

final def first()(implicit session: JdbcBackend#Session) : R

final def foreach(f: R => Unit, maxRows: Int)

(implicit session: JdbcBackend#Session): Unit

....

}

Page 49: Slick @ Confitura 2013

Lifted - predykaty

for {

speaker <- Query(Speakers)

if (speaker.name startsWith "Mac")

} yield (speaker.twitter)

====!=

notNull

Page 50: Slick @ Confitura 2013

Lifted - predykaty

for {

speaker <- Query(Speakers)

if (speaker.name startsWith "Mac")

} yield (speaker.twitter)

Rep[String]

Rep[TwitterId]

Rep[String]

Page 51: Slick @ Confitura 2013

Lifted - Join

for {

(s,p) <- Query(Speakers)

innerJoin Presentations

on (_.id === _.authorId)

} yield (s.twitter,p.abstr)

Page 52: Slick @ Confitura 2013

Lifted - własne typy

case class TwitterId(id:String) extends AnyVal

implicit val twitterId = MappedJdbcType.base[TwitterId,String]

(_.id,TwitterId.apply)

object Speakers extends Table[Speaker]("speakers") {

def twitter = column[TwitterId]("twitterId")

}

Page 53: Slick @ Confitura 2013

Lifted - kompozycja

def filter(pred

:Presentations=>Column[Boolean]) = {

for {

p <- Query(Presentations)

if (pred(p))

} yield (p.id)

}

Page 54: Slick @ Confitura 2013

Lifted - kompozycja

for {

presentation <- Query(Presentations)

author <- presentation.author

if author.name startsWith "Mac"

} yield presentation.title

Page 55: Slick @ Confitura 2013

Lifted - kompozycja

object Presentations

extends Table[Presentation] {

...

def author = foreignKey("author_fk",

authorId, Speakers)(_.id)

}

Page 56: Slick @ Confitura 2013

Lifted - podsumowanie

Page 57: Slick @ Confitura 2013

Czego brakuje lifted?

for {

speaker <- Query(Speakers)

if (speaker.name === "Mac")

} yield (speaker.twitter)

Page 58: Slick @ Confitura 2013

WIP - direct

Page 59: Slick @ Confitura 2013
Page 60: Slick @ Confitura 2013

Makra

● C - syntaktyczne

● Lisp - higieniczne

● Scala 2.10 - typowane

Page 61: Slick @ Confitura 2013

def filter(filter:T => Boolean)

: Queryable[T] =

macro QueryableMacros.filter[T]

Page 62: Slick @ Confitura 2013

def filter[T:c.WeakTypeTag]

(c: scala.reflect.macros.Context)

(projection: c.Expr[T => Boolean]) : c.Expr

[scala.slick.direct.Queryable[T]] = ...

Page 63: Slick @ Confitura 2013

Makro - przykład

.filter(s => s.name == "Henry")

("filter", Supplier, Function( List("s"), Apply( Select("s", "name"), "==",

List(Literal(Constant("Henry"))))))

Page 64: Slick @ Confitura 2013

("filter", Supplier, Function( List("s"), Apply( Select("s", "name"), "==",

List(Literal(Constant("Henry"))))))

Slick Query AST

Page 65: Slick @ Confitura 2013

SLICK - architektura

AST

H2MySQL

Lifted Direct

Page 66: Slick @ Confitura 2013

Direct - metadane

@table("presentation")

case class Presentation(@column("id") id:Long,

@column("authorId") authorId:Long,

@column("title") title:String,

@column("abstract")abstr:String)

Page 67: Slick @ Confitura 2013

Direct - przykład

val query = for {

speaker <- Queryable[Speaker]

if speaker.name == "Kuba Nabrdalik"

} yield speaker.bio

Page 68: Slick @ Confitura 2013

Direct - przykładval backend = new SlickBackend(profile,

AnnotationMapper)

def list[H](query:BaseQueryable[H])

: Iterable[H]

= backend.result(query, session)

dao.list(query) : List[Speaker]

Page 69: Slick @ Confitura 2013

Direct - typesafety :|

for {

presentation <- Queryable[Presentation]

if (presentation.title.contains("scala"))

} yield (presentation.id)

Page 70: Slick @ Confitura 2013

Direct - kompozycja??

def filter(pred:Presentation=>Boolean) = {

for {

p <- Queryable[Presentation]

if (pred(p))

} yield (presentation.id)

}

Page 71: Slick @ Confitura 2013

Slick - architektura

AST

H2MySQL

Lifted Direct

OrientDB

Page 72: Slick @ Confitura 2013

Slick OrientDB

@table("presentation")

case class Presentation(@column("id") id:Long,

@column("title") title:String,

@column("comments") comments:List[Comment])

case class Comment(@column("number") author:String,

@column("rate") rate:Integer,

@column("content") content:String)

Page 73: Slick @ Confitura 2013

Slick OrientDB

for {

presentation <- Queryable[Presentation]

if (presentation.comments

.filter(_.ratio > 5).size > 0)

} yield (presentation.title)

Page 74: Slick @ Confitura 2013

SLICK - architektura

AST

H2MySQL

Lifted Direct

OrientDBMemory

Page 75: Slick @ Confitura 2013

SLICK - architektura

AST

H2MySQL

Lifted

18 faz kompilacji...

OrientDBMemory

Direct

Page 76: Slick @ Confitura 2013

there is no valid translation of arbitrary monadic Query expressions to SQL (whose semantics are stuck half-way between applicative functors and monads)

- Stefan Zeiger

Page 77: Slick @ Confitura 2013

czy to się opłaca?● Deklaratywne zapytania

● Znane API

● Brak magii

● ... oprócz odrobiny makr

● Skomplikowane :(

Page 79: Slick @ Confitura 2013

Takk/Tänan/Dzięki

* we're hiring :)