SlideShare a Scribd company logo
ScalikeJDBC
Tutorial
for Beginners
@seratch
Kazuhiro Sera
Table of contents
What’s this?
ConnectionPool
Implicit Session
SQL Syntax
Query DSL
More Features
Get Started Now
What’s this?
ScalikeJDBC
http://git.io/scalikejdbc
A tidy SQL-based DB access library
for Scala developers.
...SQL-based?
SQL-based
import scalikejdbc._, SQLInterpolation._
val id = 123
// Anorm-like API for Scala 2.9
val name = SQL(“select name from company where id = {id}”)
.bindByName(‘id -> id).map(rs => rs.string(“name”)).single.apply()
// SQL Interpolation since 2.10
val name = sql”select name from company where id = ${id}”
.map(rs => rs.string(“name”)).single.apply()
// Query DSL
val name = withSQL {
select(c.name).from(Company as c).where.eq(c.id, id)
}.map(rs => rs.string(c.resultName.name)).single.apply()
Everybody knows SQL
We don’t need something new and
different from SQL.
Maybe, you can write the code on the
previous slide immediately, right?
Because you already know SQL.
ConnectionPool
Easy-to-use CP
DB block such as DB.readOnly { ... }
borrows a connection from
ConnectionPool.
Since ConnectionPool is a singleton
object, you can easily borrow
anywhere.
ConnectionPool
import scalikejdbc._
Class.forName(“org.h2.Driver”)
// default connection pool
val (url, user, password) = (“jdbc:h2:mem:db”, “sa”, “”)
ConnectionPool.singleton(url, user, password)
val conn: java.sql.Connection = ConnectionPool.borrow()
val names: List[String] = DB readOnly { implicit session =>
sql”select name from company”.map(_.string(“name”).list.apply()
}
// named connection pool
val poolSettings = new ConnectionPoolSettings(maxSize = 50)
ConnectionPool.add(‘secondary, url, user, passsword, poolSettings)
NamedDB(‘secondary) readOnly { implicit session =>
DBCP by default
By default, only Commons DBCP
implementation is provided.
It’s also possible to implement your
preferred connection pool.
(e.g. C3P0, BoneCP)
Implicit Session
Go implicitly
DBSession represents
java.sql.Connection
with a transaction(if exists).
#apply() requires DBSession
implicitly.
Implicit DBSession
import scalikejdbc._, SQLInterpolation._
val id = 123
// DBSession usage
val name: Option[String] = DB readOnly { session: DBSession =>
session.single(“select name from company where id = ?”, id) { rs =>
rs.string(“name”)
}
}
// SQL API requires implicit DBSession
val name: Option[String] = DB readOnly { implicit session =>
sql”select name from company where id = ${id}”
.map(_.string(“name”)).single.apply()
}
Automatic
AutoSession creates & closes an ad-
hoc session if absent.
query: read-only session
update: auto-commit session
Flexible Transaction
import scalikejdbc._, SQLInterpolation._
implicit val session = AutoSession
sql”select name from company”.map(_.string(“name”)).list.apply()
def addCompany(name: String)(implicit s: DBSession = AutoSession) {
sql”insert into company values (${name})”.update.apply()
}
def getAllNames()(implicit s: DBSession = AutoSession): List[String] = {
sql”select name from company”.map(_.string(“name”)).list.apply()
}
val names: List[String] = getAllNames() // read-only session
DB localTx { implicit session =>
addCompany(“Typesafe”) // within a transaction
getAllNames() // within a transaction, includes “Typesafe”
}
SQL Syntax
SQLSyntax?
// SQLSyntax = a part of SQL object, will be embedded as-is
val c: SQLSyntax = sqls”count(*)”
val bobby: String = “Bob%”
val query = sql”select ${c} from members where name like ${bobby}”
// -> “select count(*) from members where name like ?”
A part of SQL object which will be
embedded as-is.
SQLSyntaxSupport
SQLSyntaxSupport provides DRY and
type safe SQL.
- CoC but configurable
- Write complex join queries
- Using type-dynamic(similar to
Ruby’s method-missing) but have
compile-time check with macro
CoC Rules
// Scala object
case class GroupMember(id: Long, fullName: Option[String] = None)
obejct GroupMember extends SQLSyntaxSupport[GroupMember]
// DDL
create table group_member {
id bigint not null primary key,
full_name varchar(255)
}
Simply snake_case’d name
Customize it
// Scala object
case class GroupMember(id: Long, fullName: Option[String] = None)
obejct GroupMember extends SQLSyntaxSupport[GroupMember] {
override val tableName = “group_members”
override val nameConverters = Map(“fullName” -> “fullname”)
}
// DDL
create table group_members {
id bigint not null primary key,
fullname varchar(255)
}
Query & Extracting
import scalikejdbc._, SQLInterpolation._
// entity class (Plain Old Scala Object)
case class Member(id: Long, fullName: Option[String] = None)
// companion object for entity
obejct Member extends SQLSyntaxSupport[Member] {
def apply(m: ResultName[Member])(rs: WrappedResultSet) = new Member(
id = rs.long(m.id), name = rs.stringOpt(m.fullName)
)
)
val m = Member.syntax(“m”)
val id = 123
val memebr: Option[Member] = DB readOnly { implicit s =>
sql”select ${m.result.*} from ${Member as m} where ${m.id} = ${id}”
.map(Member(m.resultName)).single.apply()
}
result? resultName?
val m = Member.syntax(“m”)
m.fullName == “m.full_name”
m.result.fullName == “m.full_name as fn_on_m”
m.resultName.fullName == “fn_on_m”
Scala:
sql”select ${m.result.fullName} from ${Member as m} where ${m.id} = 123”
SQL:
“select m.full_name as fn_on_m from member m where m.id = 123”
ResultSet extractor:
val name = sql”...”.map(rs => rs.string(m.resultName.fullName)).single.apply()
// extracting “fn_on_m” from ResultSet
Type safe dynamic
import scalikejdbc._, SQLInterpolation._
val m = Member.syntax(“m”)
val id = 123
val memebr: Option[Member] = DB readOnly { implicit s =>
sql”select ${m.result.fullNamee} from ${Member as m} where ${m.id} = ${id}”
.map(Member(m.resultName)).single.apply()
}
<console>:28: error: Member#fullNamee not found. Expected fields are #id,
#fullName, #createdAt, #deletedAt.
m.fullNamee
^
Query DSL
Uniqueness
- DBSession inspired by Querulous
- SQL(String) inspired by Anorm
- sql”...” inspired by Slick
Query DSL is surely
ScalikeJDBC’s original
way!
What’s Query DSL
- Just appends SQL parts
- Type safe and pragmatic
- Easy to understand
- Not composable but reusable
- Parts from sqls object
- Append sqls”...” when needed
Query DSL examples
import scalikejdbc._, SQLInterpolation._
implicit val session = AutoSession
val c = Company.syntax(“c”)
val id = 123
val company: Option[Company] = withSQL {
select.from(Company as c).where.eq(c.id, id)
}.map(Company(c.resultName)).single.apply()
insert.into(Company).values(123, “Typesafe”)
val column = Company.column
update(Company).set(column.name -> “Oracle”).where.eq(column.id, 123)
delete.from(Company).where.eq(column.id, 123)
Joins, one-to-x API
val programmerWithSkills = withSQL {
select
.from(Programmer as p)
.leftJoin(Company as c).on(p.companyId, c.id)
.leftJoin(ProgrammerSkill as ps).on(ps.programmerId, p.id)
.leftJoin(Skill as s).(ps.skillId, s.id)
.where
.eq(p.id, id)
.and
.isNull(p.deletedAt)
}
.one(Programmer(p, c))
.toMany(SKill.opt(s))
.map { (pg, skills) => pg.copy(skills = skills) }
.single.apply()
Sub query, Paging
val noSkillProgrammers = withSQL {
select
.from(Programmer as p)
.leftJoin(Company as c).on(p.companyId, c.id)
.where
.notIn(p.id,
select(sqls.distinct(ps.programmerId)).from(ProgrammerSkill as ps))
.isNull(p.deletedAt)
.limit(10).offset(0)
.orderBy(p.id).desc
}
.map(Programmer(p, c))
.list.apply()
sqls.xxx, sqls”...”
val userId =
val orderCount: Long = withSQL {
select(sqls.count(sqls.distinct(o.id))) // sqls object
.from(Order as o)
.innerJoin(Product as p).on(p.id,o.productId)
.where
.append(sqls”${o.userId} = ${userId}”) // direct SQL embedding
}
.map(rs => rs.long(1))
.single.apply().get
More and More
- insert select
- groupBy, having
- in, exists, like, between
- union, unionAll
- withRoundBracket { ... }
- dynamic(And|Or)Conditions { ... }
In detail:
QueryDSLFeature.scala
QueryInterfaceSpec.scala
More Features
Code Generator
- sbt plugin
- Code from existing tables
- project/scalikejdbc.properties
- Play2 style models and tests
In detail:
Wiki Page
sbt “scalikejdbc-gen [table-name]”
Testing with ScalaTest
import scalikejdbc._, scalatest.AutoRollback
import org.scalatest.fixture.FlatSpec
class MemberSpec extends FlatSpec with AutoRollback {
override def fixture(implicit s: DBSession) {
sql”delete from members”.update.apply()
Member.create(1, “Alice”)
}
behavior of “Member”
it should “create a new record” in { implicit s =>
val beforeCount = Member.count
Member.create(123, “Brian”)
Member.count should equal(before + 1)
}
}
Testing with specs2 (1)
import scalikejdbc._, specs2.mutable.AutoRollback
import org.specs2.mutable.Specification
object MemberSpec extends Specification {
“Member should create a new record” in new MyAutoRollback {
val beforeCount = Member.count
Member.create(123, “Brian”)
Member.count should equal(before + 1)
}
}
trait MyAutoRollback extends AutoRollback {
override def fixture(implicit s: DBSession) {
sql”delete from members”.update.apply()
Member.create(1, “Alice”)
}
}
Testing with specs2 (2)
import scalikejdbc._, specs2.AutoRollback
import org.specs2.Specification
object MemberSpec extends Specification { def is =
“Member should create a new record” ! autoRollback().create
end
}
case class autoRollback() extends AutoRollback {
override def fixture(implicit s: DBSession) {
sql”delete from members”.update.apply()
Member.create(1, “Alice”)
}
def create = this {
val beforeCount = Member.count
Member.create(123, “Brian”)
Member.count should equal(before + 1)
}
}
Play2 Support
- Integrates with Play2 seamlessly
- Read conf/application.conf
- Add plugin to conf/play.plugins
- FixturePlugin is also available
- Great contribution by @tototoshi
In detail:
Wiki Page
Get Started Now
More info
Examples
devteam-app example
QueryInterfaceSpec.scala
Reference
Wiki Pages
Users Group
ScalikeJDBC Users Group
ScalikeJDBC Users Group Japan
Enjoy!
Just write SQL
and get things done!
git.io/scalikejdbc

More Related Content

PDF
Banco de Dados - MySQL Basico
PDF
Estrutura de Dados - Aula de revisão de C na prática
PDF
Chapitre5: Classes et objets
PDF
Лекция 4. Принципы SOLID
PDF
Cours c++
PPTX
PPTX
Regular Expressions 101 Introduction to Regular Expressions
Banco de Dados - MySQL Basico
Estrutura de Dados - Aula de revisão de C na prática
Chapitre5: Classes et objets
Лекция 4. Принципы SOLID
Cours c++
Regular Expressions 101 Introduction to Regular Expressions

What's hot (18)

PDF
Estrutura de Dados - PILHAS
PPTX
Estrutura de Dados - Aula 01
PPTX
У світі завжди була чума… (Зображення пошесті чуми у творах Альбера Камю та Д...
ODP
Regular Expression
PPT
Manipulation des Données , cours sql oracle
PPTX
Tipos de dados em MySQL
PDF
Polymorphisme
PDF
Pilha e filas
PPTX
Endeavor Vs. Chgman
PPTX
Database connectivity to sql server asp.net
PPTX
Tabela Hash
PPT
PL/SQL Introduction and Concepts
PPTX
Basic sql Commands
PPSX
Sql triggers
PDF
[Curso Java Basico] Aula 14: Condicionais If-Else
PPTX
Introduction to SQL
PPT
Working with Databases and MySQL
PPT
Mysql Ppt
Estrutura de Dados - PILHAS
Estrutura de Dados - Aula 01
У світі завжди була чума… (Зображення пошесті чуми у творах Альбера Камю та Д...
Regular Expression
Manipulation des Données , cours sql oracle
Tipos de dados em MySQL
Polymorphisme
Pilha e filas
Endeavor Vs. Chgman
Database connectivity to sql server asp.net
Tabela Hash
PL/SQL Introduction and Concepts
Basic sql Commands
Sql triggers
[Curso Java Basico] Aula 14: Condicionais If-Else
Introduction to SQL
Working with Databases and MySQL
Mysql Ppt
Ad

Viewers also liked (15)

KEY
Learning from "Effective Scala"
PDF
States of Dolphin - MySQL最新技術情報2013秋 -
PDF
MySQL最新情報 ※2015年9月5日「第1回 関西DB勉強会」での発表資料
PDF
MySQL最新動向と便利ツールMySQL Workbench
PDF
20160929 inno db_fts_jp
PDF
MySQL最新情報  ※2016年12月
PDF
SQL+NoSQL!? それならMySQL Clusterでしょ。
PDF
MySQL Casual Talks Vol.4 「MySQL-5.6で始める全文検索 〜InnoDB FTS編〜」
PDF
20150920 中国地方db勉強会
PDF
いろいろ考えると日本語の全文検索もMySQLがいいね!
PDF
MySQL 5.7 InnoDB 日本語全文検索(その2)
PDF
Windows環境でのMySQL
PDF
MySQL 5.7 InnoDB 日本語全文検索
PDF
Full Text Search In PostgreSQL
PDF
MySQL 5.7にやられないためにおぼえておいてほしいこと
Learning from "Effective Scala"
States of Dolphin - MySQL最新技術情報2013秋 -
MySQL最新情報 ※2015年9月5日「第1回 関西DB勉強会」での発表資料
MySQL最新動向と便利ツールMySQL Workbench
20160929 inno db_fts_jp
MySQL最新情報  ※2016年12月
SQL+NoSQL!? それならMySQL Clusterでしょ。
MySQL Casual Talks Vol.4 「MySQL-5.6で始める全文検索 〜InnoDB FTS編〜」
20150920 中国地方db勉強会
いろいろ考えると日本語の全文検索もMySQLがいいね!
MySQL 5.7 InnoDB 日本語全文検索(その2)
Windows環境でのMySQL
MySQL 5.7 InnoDB 日本語全文検索
Full Text Search In PostgreSQL
MySQL 5.7にやられないためにおぼえておいてほしいこと
Ad

Similar to ScalikeJDBC Tutorial for Beginners (20)

ODP
Slickdemo
PDF
Scala active record
PDF
Using Scala Slick at FortyTwo
PDF
TreSQL
PDF
Solid and Sustainable Development in Scala
PDF
Solid And Sustainable Development in Scala
PDF
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_tech
PDF
groovy databases
PDF
Http4s, Doobie and Circe: The Functional Web Stack
PDF
DConf 2016 std.database (a proposed interface & implementation)
PDF
Spring Day | Spring and Scala | Eberhard Wolff
PDF
Introduction to Quill
PPTX
Spark sql
PDF
Scala and Spring
PDF
Юрий Буянов «Squeryl — ORM с человеческим лицом»
PDF
Querydsl fin jug - june 2012
PDF
Alternatives of JPA/Hibernate
PPT
Java Database Connectivity (JDBC) with Spring Framework is a powerful combina...
PPTX
Apache Spark in your likeness - low and high level customization
PDF
Database programming including O/R mapping (as part of the the PTT lecture)
Slickdemo
Scala active record
Using Scala Slick at FortyTwo
TreSQL
Solid and Sustainable Development in Scala
Solid And Sustainable Development in Scala
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_tech
groovy databases
Http4s, Doobie and Circe: The Functional Web Stack
DConf 2016 std.database (a proposed interface & implementation)
Spring Day | Spring and Scala | Eberhard Wolff
Introduction to Quill
Spark sql
Scala and Spring
Юрий Буянов «Squeryl — ORM с человеческим лицом»
Querydsl fin jug - june 2012
Alternatives of JPA/Hibernate
Java Database Connectivity (JDBC) with Spring Framework is a powerful combina...
Apache Spark in your likeness - low and high level customization
Database programming including O/R mapping (as part of the the PTT lecture)

More from Kazuhiro Sera (20)

PDF
All I learned while working on a Scala OSS project for over six years #ScalaM...
PDF
Contributing to Scala OSS from East Asia #ScalaMatsuri
PDF
Skinny Meetup Tokyo 2 日本語スライド
PDF
Skinny 2 Update
PDF
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarcon
PDF
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
PDF
Future on Servlet #scala_ks
PDF
Servlet と Future の関わり方 #scala_ks
PDF
マイクロサービス運用の所感 #m3dev
PDF
Scala が支える医療系ウェブサービス #jissenscala
PDF
Scala on Rails #rakutentech
PDF
Beginning Scala with Skinny Framework #jjug_ccc
PDF
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
PDF
Skinny Framework 1.0.0
PDF
Skinny Framework Progress Situation
PDF
Skinny Framework 進捗どうですか? #fud_scala
PDF
テストの運用について #m3dev
PDF
めんどくさくない Scala #kwkni_scala
PDF
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech
PDF
テストを書くのが嫌いな君へ #m3dev
All I learned while working on a Scala OSS project for over six years #ScalaM...
Contributing to Scala OSS from East Asia #ScalaMatsuri
Skinny Meetup Tokyo 2 日本語スライド
Skinny 2 Update
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarcon
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Future on Servlet #scala_ks
Servlet と Future の関わり方 #scala_ks
マイクロサービス運用の所感 #m3dev
Scala が支える医療系ウェブサービス #jissenscala
Scala on Rails #rakutentech
Beginning Scala with Skinny Framework #jjug_ccc
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
Skinny Framework 1.0.0
Skinny Framework Progress Situation
Skinny Framework 進捗どうですか? #fud_scala
テストの運用について #m3dev
めんどくさくない Scala #kwkni_scala
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech
テストを書くのが嫌いな君へ #m3dev

Recently uploaded (20)

PDF
cuic standard and advanced reporting.pdf
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
MYSQL Presentation for SQL database connectivity
PPTX
Spectroscopy.pptx food analysis technology
PDF
NewMind AI Weekly Chronicles - August'25 Week I
DOCX
The AUB Centre for AI in Media Proposal.docx
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Understanding_Digital_Forensics_Presentation.pptx
cuic standard and advanced reporting.pdf
“AI and Expert System Decision Support & Business Intelligence Systems”
Reach Out and Touch Someone: Haptics and Empathic Computing
Dropbox Q2 2025 Financial Results & Investor Presentation
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
MIND Revenue Release Quarter 2 2025 Press Release
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
MYSQL Presentation for SQL database connectivity
Spectroscopy.pptx food analysis technology
NewMind AI Weekly Chronicles - August'25 Week I
The AUB Centre for AI in Media Proposal.docx
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Digital-Transformation-Roadmap-for-Companies.pptx
sap open course for s4hana steps from ECC to s4
Review of recent advances in non-invasive hemoglobin estimation
Spectral efficient network and resource selection model in 5G networks
Understanding_Digital_Forensics_Presentation.pptx

ScalikeJDBC Tutorial for Beginners

  • 2. Table of contents What’s this? ConnectionPool Implicit Session SQL Syntax Query DSL More Features Get Started Now
  • 4. ScalikeJDBC http://git.io/scalikejdbc A tidy SQL-based DB access library for Scala developers. ...SQL-based?
  • 5. SQL-based import scalikejdbc._, SQLInterpolation._ val id = 123 // Anorm-like API for Scala 2.9 val name = SQL(“select name from company where id = {id}”) .bindByName(‘id -> id).map(rs => rs.string(“name”)).single.apply() // SQL Interpolation since 2.10 val name = sql”select name from company where id = ${id}” .map(rs => rs.string(“name”)).single.apply() // Query DSL val name = withSQL { select(c.name).from(Company as c).where.eq(c.id, id) }.map(rs => rs.string(c.resultName.name)).single.apply()
  • 6. Everybody knows SQL We don’t need something new and different from SQL. Maybe, you can write the code on the previous slide immediately, right? Because you already know SQL.
  • 8. Easy-to-use CP DB block such as DB.readOnly { ... } borrows a connection from ConnectionPool. Since ConnectionPool is a singleton object, you can easily borrow anywhere.
  • 9. ConnectionPool import scalikejdbc._ Class.forName(“org.h2.Driver”) // default connection pool val (url, user, password) = (“jdbc:h2:mem:db”, “sa”, “”) ConnectionPool.singleton(url, user, password) val conn: java.sql.Connection = ConnectionPool.borrow() val names: List[String] = DB readOnly { implicit session => sql”select name from company”.map(_.string(“name”).list.apply() } // named connection pool val poolSettings = new ConnectionPoolSettings(maxSize = 50) ConnectionPool.add(‘secondary, url, user, passsword, poolSettings) NamedDB(‘secondary) readOnly { implicit session =>
  • 10. DBCP by default By default, only Commons DBCP implementation is provided. It’s also possible to implement your preferred connection pool. (e.g. C3P0, BoneCP)
  • 12. Go implicitly DBSession represents java.sql.Connection with a transaction(if exists). #apply() requires DBSession implicitly.
  • 13. Implicit DBSession import scalikejdbc._, SQLInterpolation._ val id = 123 // DBSession usage val name: Option[String] = DB readOnly { session: DBSession => session.single(“select name from company where id = ?”, id) { rs => rs.string(“name”) } } // SQL API requires implicit DBSession val name: Option[String] = DB readOnly { implicit session => sql”select name from company where id = ${id}” .map(_.string(“name”)).single.apply() }
  • 14. Automatic AutoSession creates & closes an ad- hoc session if absent. query: read-only session update: auto-commit session
  • 15. Flexible Transaction import scalikejdbc._, SQLInterpolation._ implicit val session = AutoSession sql”select name from company”.map(_.string(“name”)).list.apply() def addCompany(name: String)(implicit s: DBSession = AutoSession) { sql”insert into company values (${name})”.update.apply() } def getAllNames()(implicit s: DBSession = AutoSession): List[String] = { sql”select name from company”.map(_.string(“name”)).list.apply() } val names: List[String] = getAllNames() // read-only session DB localTx { implicit session => addCompany(“Typesafe”) // within a transaction getAllNames() // within a transaction, includes “Typesafe” }
  • 17. SQLSyntax? // SQLSyntax = a part of SQL object, will be embedded as-is val c: SQLSyntax = sqls”count(*)” val bobby: String = “Bob%” val query = sql”select ${c} from members where name like ${bobby}” // -> “select count(*) from members where name like ?” A part of SQL object which will be embedded as-is.
  • 18. SQLSyntaxSupport SQLSyntaxSupport provides DRY and type safe SQL. - CoC but configurable - Write complex join queries - Using type-dynamic(similar to Ruby’s method-missing) but have compile-time check with macro
  • 19. CoC Rules // Scala object case class GroupMember(id: Long, fullName: Option[String] = None) obejct GroupMember extends SQLSyntaxSupport[GroupMember] // DDL create table group_member { id bigint not null primary key, full_name varchar(255) } Simply snake_case’d name
  • 20. Customize it // Scala object case class GroupMember(id: Long, fullName: Option[String] = None) obejct GroupMember extends SQLSyntaxSupport[GroupMember] { override val tableName = “group_members” override val nameConverters = Map(“fullName” -> “fullname”) } // DDL create table group_members { id bigint not null primary key, fullname varchar(255) }
  • 21. Query & Extracting import scalikejdbc._, SQLInterpolation._ // entity class (Plain Old Scala Object) case class Member(id: Long, fullName: Option[String] = None) // companion object for entity obejct Member extends SQLSyntaxSupport[Member] { def apply(m: ResultName[Member])(rs: WrappedResultSet) = new Member( id = rs.long(m.id), name = rs.stringOpt(m.fullName) ) ) val m = Member.syntax(“m”) val id = 123 val memebr: Option[Member] = DB readOnly { implicit s => sql”select ${m.result.*} from ${Member as m} where ${m.id} = ${id}” .map(Member(m.resultName)).single.apply() }
  • 22. result? resultName? val m = Member.syntax(“m”) m.fullName == “m.full_name” m.result.fullName == “m.full_name as fn_on_m” m.resultName.fullName == “fn_on_m” Scala: sql”select ${m.result.fullName} from ${Member as m} where ${m.id} = 123” SQL: “select m.full_name as fn_on_m from member m where m.id = 123” ResultSet extractor: val name = sql”...”.map(rs => rs.string(m.resultName.fullName)).single.apply() // extracting “fn_on_m” from ResultSet
  • 23. Type safe dynamic import scalikejdbc._, SQLInterpolation._ val m = Member.syntax(“m”) val id = 123 val memebr: Option[Member] = DB readOnly { implicit s => sql”select ${m.result.fullNamee} from ${Member as m} where ${m.id} = ${id}” .map(Member(m.resultName)).single.apply() } <console>:28: error: Member#fullNamee not found. Expected fields are #id, #fullName, #createdAt, #deletedAt. m.fullNamee ^
  • 25. Uniqueness - DBSession inspired by Querulous - SQL(String) inspired by Anorm - sql”...” inspired by Slick Query DSL is surely ScalikeJDBC’s original way!
  • 26. What’s Query DSL - Just appends SQL parts - Type safe and pragmatic - Easy to understand - Not composable but reusable - Parts from sqls object - Append sqls”...” when needed
  • 27. Query DSL examples import scalikejdbc._, SQLInterpolation._ implicit val session = AutoSession val c = Company.syntax(“c”) val id = 123 val company: Option[Company] = withSQL { select.from(Company as c).where.eq(c.id, id) }.map(Company(c.resultName)).single.apply() insert.into(Company).values(123, “Typesafe”) val column = Company.column update(Company).set(column.name -> “Oracle”).where.eq(column.id, 123) delete.from(Company).where.eq(column.id, 123)
  • 28. Joins, one-to-x API val programmerWithSkills = withSQL { select .from(Programmer as p) .leftJoin(Company as c).on(p.companyId, c.id) .leftJoin(ProgrammerSkill as ps).on(ps.programmerId, p.id) .leftJoin(Skill as s).(ps.skillId, s.id) .where .eq(p.id, id) .and .isNull(p.deletedAt) } .one(Programmer(p, c)) .toMany(SKill.opt(s)) .map { (pg, skills) => pg.copy(skills = skills) } .single.apply()
  • 29. Sub query, Paging val noSkillProgrammers = withSQL { select .from(Programmer as p) .leftJoin(Company as c).on(p.companyId, c.id) .where .notIn(p.id, select(sqls.distinct(ps.programmerId)).from(ProgrammerSkill as ps)) .isNull(p.deletedAt) .limit(10).offset(0) .orderBy(p.id).desc } .map(Programmer(p, c)) .list.apply()
  • 30. sqls.xxx, sqls”...” val userId = val orderCount: Long = withSQL { select(sqls.count(sqls.distinct(o.id))) // sqls object .from(Order as o) .innerJoin(Product as p).on(p.id,o.productId) .where .append(sqls”${o.userId} = ${userId}”) // direct SQL embedding } .map(rs => rs.long(1)) .single.apply().get
  • 31. More and More - insert select - groupBy, having - in, exists, like, between - union, unionAll - withRoundBracket { ... } - dynamic(And|Or)Conditions { ... } In detail: QueryDSLFeature.scala QueryInterfaceSpec.scala
  • 33. Code Generator - sbt plugin - Code from existing tables - project/scalikejdbc.properties - Play2 style models and tests In detail: Wiki Page sbt “scalikejdbc-gen [table-name]”
  • 34. Testing with ScalaTest import scalikejdbc._, scalatest.AutoRollback import org.scalatest.fixture.FlatSpec class MemberSpec extends FlatSpec with AutoRollback { override def fixture(implicit s: DBSession) { sql”delete from members”.update.apply() Member.create(1, “Alice”) } behavior of “Member” it should “create a new record” in { implicit s => val beforeCount = Member.count Member.create(123, “Brian”) Member.count should equal(before + 1) } }
  • 35. Testing with specs2 (1) import scalikejdbc._, specs2.mutable.AutoRollback import org.specs2.mutable.Specification object MemberSpec extends Specification { “Member should create a new record” in new MyAutoRollback { val beforeCount = Member.count Member.create(123, “Brian”) Member.count should equal(before + 1) } } trait MyAutoRollback extends AutoRollback { override def fixture(implicit s: DBSession) { sql”delete from members”.update.apply() Member.create(1, “Alice”) } }
  • 36. Testing with specs2 (2) import scalikejdbc._, specs2.AutoRollback import org.specs2.Specification object MemberSpec extends Specification { def is = “Member should create a new record” ! autoRollback().create end } case class autoRollback() extends AutoRollback { override def fixture(implicit s: DBSession) { sql”delete from members”.update.apply() Member.create(1, “Alice”) } def create = this { val beforeCount = Member.count Member.create(123, “Brian”) Member.count should equal(before + 1) } }
  • 37. Play2 Support - Integrates with Play2 seamlessly - Read conf/application.conf - Add plugin to conf/play.plugins - FixturePlugin is also available - Great contribution by @tototoshi In detail: Wiki Page
  • 39. More info Examples devteam-app example QueryInterfaceSpec.scala Reference Wiki Pages Users Group ScalikeJDBC Users Group ScalikeJDBC Users Group Japan
  • 40. Enjoy! Just write SQL and get things done! git.io/scalikejdbc