introduction to quill
TRANSCRIPT
![Page 1: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/1.jpg)
1
COMPILE-TIME LANGUAGEINTEGRATED QUERIES FOR SCALA
Mateusz Bilski
![Page 2: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/2.jpg)
2
SCALA SELLING POINTStype safety and inferencecompiler works for youno need to unit test everything
![Page 3: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/3.jpg)
3
SQL
val db = Database.forConfig("database") db.run(sql"SELECT * FROM users WHERE id=${id}".as[User].headOption)
DSL
val users = TableQuery[User] db.run(users.filter(_.id == 1).result.headOption)
Lists
val users = List(User(1), User(2), User(3)) users.filter(_.id == 1).headOption
![Page 4: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/4.jpg)
3
4
WHAT IS QUILL?Quoted Domain Specific LanguageSlick alternativeAsynchronous SQL clientCassandra supportBoilerplate free mappingCompile time query generation and validation
![Page 5: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/5.jpg)
5
BACKGROUNDInspired by
(2013) white paper.First commit at Jul 19, 2015.Current release is 0.7.0.Stable version planned for Summer 2016.
A Practical Theory of Language-IntegratedQuery
![Page 6: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/6.jpg)
6
AUTHORFlavio W. Brasil
So�ware engineer at Twitter
Created and clump activate
![Page 7: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/7.jpg)
7
ENOUGH. LET'S SEE SOME CODE!
![Page 8: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/8.jpg)
8
build.sbt
libraryDependencies += "io.getquill" %% "quill-async" % "0.6.0"
application.conf
db.default { host = "localhost" port = 3306 user = "root" database = "quill" }
![Page 9: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/9.jpg)
8
9
evolutions.sql
CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, is_active BOOLEAN NOT NULL );
CREATE TABLE devices ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, user_id INT NOT NULL );
![Page 10: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/10.jpg)
9
10
Source definition
lazy val db = source { new MysqlAsyncSourceConfig[SnakeCase]("db.default") }
Model definition
case class User(id: Long, name: String, isActive: Boolean) case class Device(id: Long, name: String, userId: Long)
Schema
val Users = quote(query[User].schema(_.generated(_.id))) val Devices = quote(query[Device].schema(_.generated(_.id)))
![Page 11: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/11.jpg)
10
11
Queriesdef byId(id: Long) = quote { Users.filter(_.id == lift(id)) }
def byIdWithDevices(id: Long) = quote { table .leftJoin(DevicesRepository.table) .on((u, d) => u.id == d.userId) .filter(_._1.id == lift(id)) }
Executiondef find(id: Long): Future[Option[User]] = db.run(byId(id)).map(_.headOption)
def findWithDevices(id: Long): Future[List[(User, Option[Device])]] = db.run(byIdWithDevices(id))
![Page 12: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/12.jpg)
11
12
CRUD
def create(user: User): Future[User] = { db.run(Users.insert)(List(user)).map { newId => user.copy(id = newId.head) } }
def update(user: User): Future[List[Long]] = { db.run(byId(user.id).update)(List(user)) }
def delete(user: User): Future[List[User]] = { db.run(byId(user.id).delete) }
![Page 13: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/13.jpg)
12
13
Dynamic queries
val r = scala.util.Random
def dynamic: Quoted[Query[User]] = quote { table.filter(_.isActive == r.nextBoolean()) }
![Page 14: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/14.jpg)
13
14
Logs
Service.scala:13: SELECT x3.id, x3.name, x3.is_active FROM users x3
WHERE x3.id = ?
Service.scala:16: SELECT u.id, u.name, u.is_active, d.id, d.name, d.user_id
FROM users u LEFT JOIN devices d ON u.id = d.user_id
WHERE u.id = ?
Service.scala:19: INSERT INTO users (name,is_active) VALUES (?, ?)
Service.scala:25: UPDATE users SET id = ?, name = ?, is_active = ?
WHERE id = ?
Service.scala:29: DELETE FROM users WHERE id = ?
Service.scala:33: Dynamic query
![Page 15: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/15.jpg)
14
15
QUERY PROBING DEMO
![Page 16: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/16.jpg)
16
HOW DOES THE QUERY GENERATION WORK?
![Page 17: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/17.jpg)
17
Query
quote { for { c <- couples w <- people m <- people if (c.her == w.name && c.him == m.name && w.age > m.age) } yield { (w.name, w.age - m.age) } }
![Page 18: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/18.jpg)
17
18
AST
FlatMap(Entity(Couple, None, List()), Ident(c), FlatMap(Entity(Person, None, List()), Ident(w), Map(Filter(Entity(Person, None, List()), Ident(m),BinaryOperation(BinaryOperation(BinaryOperation( Property(Ident(c), her), ==, Property(Ident(w), name)), &&, BinaryOperation(Property(Ident(c), him), ==, Property(Ident(m), name))), &&, BinaryOperation( Property(Ident(h), age), >, Property(Ident(m), age)))), Ident(m), Tuple(List(Property(Ident(m), name), BinaryOperation(Property(Ident(w), age), -, Property(Ident(m), age))))))
![Page 19: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/19.jpg)
18
19
Normalisation
![Page 20: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/20.jpg)
19
20
AST + Normalisation = SQL
SELECT w.name, w.age - m.age FROM couples c, people w, people m WHERE c.her = w.name AND c.him = m.name AND w.age > m.age;
![Page 21: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/21.jpg)
20
21
QUILL VS SLICKQUILL
Language Integrated QueryQuoted DSLMapping using simple case classesCompile time query generationFully asynchronous non-blocking database accessQuery extensibility
SLICK
Functional Relational MappingEmbedded DSLExplicit type definitionRuntime query generationAsynchronous wrapper on top of jdbcRaw statements
![Page 22: Introduction to Quill](https://reader030.vdocument.in/reader030/viewer/2022021502/58f2c8681a28ab0b148b45ef/html5/thumbnails/22.jpg)
22
PROBLEMSusage of whitebox macroslack of batch operationsunstable query probingimplemented by one guyno production usage reported yet