220 likes | 398 Views
What is Slick and why we use it?. Mark van der Tol. Why we moved to SQL. MongoDB has No joins or referential integrity No transactions Max element size for index A dvantages PostgreSQL has Better indexes Better tooling Strict schema. Problem faced with MongoDB.
E N D
What is Slick and why we use it? Mark van der Tol
Why we moved to SQL MongoDB has • No joins or referential integrity • No transactions • Max element size for index Advantages PostgreSQL has • Better indexes • Better tooling • Strict schema
Problem faced with MongoDB Query unseen alerts for users Data: { "message": "Example alert", "seenBy": [...] } Query: { "seenBy": { "$ne": "user" } } Max element size for indexed elements: 1 KB
Trivial in SQL SELECT message FROM alerts WHERE id NOT IN ( SELECT messageId FROM views WHERE user = "user" )
MongoDB • We keep using Mongo for statistics data • Easier to shard/replicate • No schema enforcement
What is Slick • Database query library for Scala • Table mapping • Strongly typed • Collection like syntax
Available for • DB2* • Derby/JavaDB • H2 • HSQLDB/HyperSQL • Microsoft Access • Microsoft SQL Server • MySQL • Oracle* • PostgreSQL • SQLite *Requires subscription for production use
Database connection importscala.slick.driver.PostgresDriver.simple._ importDatabase.threadLocalSession Database.forURL("jdbc:postgresql://…", driver = "org.postgresql.Driver") withSession {//session is now implicitly available in thread-localstorage } Database.forURL("jdbc:postgresql://…", driver = "org.postgresql.Driver") withTransaction {//session is now implicitly available in thread-local storage }
Table definition objectCoffeeTable extends Table[(String, BigDecimal, Int)]("COFFEE") { def name = column[String]("NAME", O.PrimaryKey)def price = column[BigDecimal]("PRICE")def sales = column[Int]("SALES") def * = name ~ price ~ sales }
Simple SELECT query val minPrice: BigDecimal = 1.0 val query = for { c <- CoffeeTable if (c.price >= minPrice) } yield (c.name) val names = query.list
Table definition for Case class caseclassCoffee (name: String, price: BigDecimal, sales: Int) objectCoffeeTable extendsTable[Coffee]("coffee") { def name = column[String]("NAME", O.PrimaryKey)def price = column[BigDecimal]("PRICE")def sales = column[Int]("SALES")def * = name ~ price ~ sales <> (Coffee, Coffee.unapply _) }
Simple SELECT query val query = for { c <- CoffeeTable } yield (c) val coffees = query.list
SELECT query with join val query = for{ p <- PersonTable c <- CoffeeTable if(p.favoriteCoffee === c.name) } yield (p.name, c.name, c.price)
INSERT query CoffeeTable.insert( Coffee("Java", 2.50, 0) )
UPDATE/DELETE query val query = for { c <- CoffeeTable if (c.price < 1.50) } yield (c.price) query.update(1.50) query.delete
Plain SQL queries val query = StaticQuery .query[BigDecimal, (String, Int)]( """select c.name, c.sales from coffees c where c.price < ?""" )
Features not shown • Queries with parameters • Extensible: Add own types and functions • "Direct embedding"
Features • Query library that stays close to SQL • Hides dbms specific syntax • Prevents SQL-injections • Many checks compile time
Disadvantages • DSL not always intuitive • Difficult compile errors • Focus on single thread usage • Not very comprehensive documentation
Multi-threaded use workaround val session = Database.forURL("jdbc:…", driver = “…").createSession() session.conn.setAutoCommit(false) //prevent Slick from creating transactions itself session.asInstanceOf[BaseSession].inTransaction = true … session.conn.commit() session.close()
Resources • Slick: http://slick.typesafe.com/http://groups.google.com/group/scalaquery • Sheets: http://www.plotprojects.com/