Slick @ Confitura 2013
-
Upload
maciek-prochniak -
Category
Software
-
view
89 -
download
0
description
Transcript of Slick @ Confitura 2013
Maciek Próchniak
Jak udawaćże nie mamybazy danych
Oracle view
DDD/OOP view
Larry
Uncle Bob
Repozytorium?
public interface Repository<T> {
void save(T object);
Collection<T> loadAll();
T load(Id id);
}
Repozytorium?
public interface Repository<Presentation> {
Collection<Presentation>
findByCategoryWithPopularityGreaterThan
(String name, double popularity, int limit);
...
}
Zapytania też mogą być
logiką!
Dashboard
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;
Techniki
● JDBC
● i(my??)Batis
● Hibernate/JPA
● Hades
● SpringData
● jOOQ
● OneWEBSQL
Object/Relational Mapping is the Vietnam of Computer Science
- Ted Neward
ORM - OMG- Rich Hickey
SQL?
SELECT p.* from PRESENTATIONS p, AUTHORS a where p.authorId = a.id and p.popularity > :popularity and a.name = :name
SQL - kompozycja???
???
.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};
JVM?
map
tasks
:List[Task]
convert:Task->View
tasks.map(convert) : List[View]
flatMap
tasks:List[Task]
createSubtasks:Task->List[Task]
tasks.flatMap(createSubtasks):List[Task]
Kolekcje - Scala!
presentations.flatMap(presentation =>
authors
.filter(author =>
author.id == presentation.authorId)
.filter(author => author.name == name
&& presentation.popularity > popularity)
.map(_ => presentation)
)
Kolekcje - Scala!
for {
presentation <- presentations
author <- authors
if (author.id == presentation.authorId)
if (author.name == name &&
presentation.popularity > popularity)
} yield presentation
SQL - Scala
SELECT p.* from PRESENTATIONS p
for {p <- presentations
} yield p
Filtrowanie
SELECT p.* from PRESENTATIONS pWHERE p.rank > 5
for {p <- presentationsif p.rank > 5
} yield p
Projekcja
SELECT p.name from PRESENTATIONS pWHERE p.rank > 5
for {p <- presentationsif p.rank > 5
} yield p.name
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)
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)
Order by, limit
SELECT p.* from PRESENTATIONS porder by p.namelimit 10
(for {p <- presentations
} yield p).sortBy(_.name).take(10)
Deklaratywność w Scali
tasks
.map(_.name)
.filter(_.priority > 4)
.take(3)
● Statyczne typowanie
● Deklaratywność
● Predykaty = wyrażenia Scali
● Standardowe API - (flat)Map
Logika DAO DB
findByNameOrderByTypefindByTypeGroupByCategory
...
Logika DAO DB
query
???
Scala
Language
Integrated
Connectivity
Kit
Play!
Akka
Slick
Scala
Typesafe
Slick
● Obsługa różnych baz
● Łatwa konfiguracja
● DML
● Ochrona przed SQL injection
● bla
● bla
● bla
zapytania ~
operacje na kolekcjachScali
SLICK - architektura
AST
H2MySQL
Lifted
Lifted - predykaty
for {
speaker <- Query(Speakers)
if (speaker.name startsWith "Maciek")
} yield (speaker.twitter)
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 _)
}
Lifted - predykaty
for {
speaker <- Query(Speakers)
if (speaker.name startsWith "Maciek")
} yield (speaker.twitter)
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]
}
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
....
}
Lifted - predykaty
for {
speaker <- Query(Speakers)
if (speaker.name startsWith "Mac")
} yield (speaker.twitter)
====!=
notNull
Lifted - predykaty
for {
speaker <- Query(Speakers)
if (speaker.name startsWith "Mac")
} yield (speaker.twitter)
Rep[String]
Rep[TwitterId]
Rep[String]
Lifted - Join
for {
(s,p) <- Query(Speakers)
innerJoin Presentations
on (_.id === _.authorId)
} yield (s.twitter,p.abstr)
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")
}
Lifted - kompozycja
def filter(pred
:Presentations=>Column[Boolean]) = {
for {
p <- Query(Presentations)
if (pred(p))
} yield (p.id)
}
Lifted - kompozycja
for {
presentation <- Query(Presentations)
author <- presentation.author
if author.name startsWith "Mac"
} yield presentation.title
Lifted - kompozycja
object Presentations
extends Table[Presentation] {
...
def author = foreignKey("author_fk",
authorId, Speakers)(_.id)
}
Lifted - podsumowanie
Czego brakuje lifted?
for {
speaker <- Query(Speakers)
if (speaker.name === "Mac")
} yield (speaker.twitter)
WIP - direct
Makra
● C - syntaktyczne
● Lisp - higieniczne
● Scala 2.10 - typowane
def filter(filter:T => Boolean)
: Queryable[T] =
macro QueryableMacros.filter[T]
def filter[T:c.WeakTypeTag]
(c: scala.reflect.macros.Context)
(projection: c.Expr[T => Boolean]) : c.Expr
[scala.slick.direct.Queryable[T]] = ...
Makro - przykład
.filter(s => s.name == "Henry")
("filter", Supplier, Function( List("s"), Apply( Select("s", "name"), "==",
List(Literal(Constant("Henry"))))))
("filter", Supplier, Function( List("s"), Apply( Select("s", "name"), "==",
List(Literal(Constant("Henry"))))))
Slick Query AST
SLICK - architektura
AST
H2MySQL
Lifted Direct
Direct - metadane
@table("presentation")
case class Presentation(@column("id") id:Long,
@column("authorId") authorId:Long,
@column("title") title:String,
@column("abstract")abstr:String)
Direct - przykład
val query = for {
speaker <- Queryable[Speaker]
if speaker.name == "Kuba Nabrdalik"
} yield speaker.bio
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]
Direct - typesafety :|
for {
presentation <- Queryable[Presentation]
if (presentation.title.contains("scala"))
} yield (presentation.id)
Direct - kompozycja??
def filter(pred:Presentation=>Boolean) = {
for {
p <- Queryable[Presentation]
if (pred(p))
} yield (presentation.id)
}
Slick - architektura
AST
H2MySQL
Lifted Direct
OrientDB
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)
Slick OrientDB
for {
presentation <- Queryable[Presentation]
if (presentation.comments
.filter(_.ratio > 5).size > 0)
} yield (presentation.title)
SLICK - architektura
AST
H2MySQL
Lifted Direct
OrientDBMemory
SLICK - architektura
AST
H2MySQL
Lifted
18 faz kompilacji...
OrientDBMemory
Direct
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
czy to się opłaca?● Deklaratywne zapytania
● Znane API
● Brak magii
● ... oprócz odrobiny makr
● Skomplikowane :(
http://slick.typesafe.com
https://github.com/slick/slick
https://github.com/mproch/slick-orientdb
Takk/Tänan/Dzięki
* we're hiring :)