SlideShare una empresa de Scribd logo
1 de 84
Descargar para leer sin conexión
Scala-ActiveRecord
Type-safe Active Record model for Scala
@teppei_tosa_en
Who am I
鉄平 土佐
TEPPEI TOSA
iron peace place name
The first official conference in Japan.
http://scalaconf.jp/en/
Typesafe members came to
Japan and gave speeches.
Talked about the case example of building
our original BRMS “BIWARD” in Scala.
Japanese engineers talked about
Scala tips or their libraries.
• “Stackable-controller” by @gakuzzzz
https://github.com/t2v/stackable-controller
• “How we write and use Scala libraries not
to cry” by @tototoshi
http://tototoshi.github.io/slides/how-we-write-and-use-scala-libraries-
scalaconfjp2013/#1
For example,
http://scalaconf.jp/en/
Scala-ActiveRecord
Type-safe Active Record model for Scala
• https://github.com/aselab/scala-activerecord
• Latest version : 0.2.2
• Licence : MIT
Features
• Squeryl wrapper
• type-safe (most part)
• Rails ActiveRecord-like operability
• Auto transaction control
• validations
• Associations
• Testing support
Most of the other
ORM Libraries
Wrap SQL
val selectCountries = SQL(“Select * from Countries”)
Have to define mappings from the results of SQL to
the models.
val countries = selectCountries().map(row =>
row[String](“code”) -> row[String](“name”)
).toList
The motivation of
Scala-ActiveRecord
• Want to define the model mapping more
easily.
• Want not to define the find methods in
each model classes.
• Want not to write SQLs.
Other libraries example
1. Anorm
2. Slick ( ScalaQuery )
3. Squeryl
1.Anorm
• Anorm doesn’t have the Model layer.
• Have to define similar methods in each
Class.
case class Person(id:Pk[Long], name:String)
object Person {
! def create(person:Person):Unit = {
! ! DB.withConnection { implicit connection =>
! ! ! SQL("insert int person(name) values ({name}")
! ! ! ! .on('name -> person.name)
! ! ! ! .executeUpdate()
! ! }
! }
! ...
}
2. Slick ( ScalaQuery )
• Query Interface is good.
• Definding tables syntax is redundant.
• Have to define the mapping between table
and model in each table.
case class Member(id:Int, name:String, email:Option[String])
object Members extends Table[Member]("MEMBERS") {
! def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
! def name = column[String]("Name")
! def email = column[Option[String]]("EMAIL")
! def * = id.? ~ name ~ email <> (Member, Member.unapply _)
}
3. Squeryl
• The best one in these libraries.
• Scala-ActiveRecord wraps this with some
improvement.
1. Optimize the generated SQLs
2. Automate the transaction control
3. Use CoC approach to build relationship
When queries are combined
Squeryl generates sub-query SQL.
Squeryl
val query = from(table)(t => where(t.id.~ > 20) select(t))
from(query)(t => where(t.name like "%test%) select(t))
Scala
select * from
! (Select * from table where table.id > 20) q1
where q1.name like "test"
SQL
It negatively affect performance.
When queries are combined
Squeryl generates sub-query SQL.
Scala-ActiveRecord
val query = Table.where(_.id.~ > 20)
query.where(_.name like "%test%").toList
Scala
select * from table
where table.id > 20 and table.name like "test"
SQL
It can generate more simple SQL statement.
Automate
the transaction control
Squeryl
Scala-ActiveRecord
• Call “inTransaction” automatically at accessing
Iterable#iterator.
• When the save or delete method is called,
“inTransaction” is executed by default.
• Off course, you can call “inTransaction” expressly.
inTransaction {
books.insert(new Author(1, "Michel","Folco"))! !
val a = from(authors)
(a=> where(a.lastName === "Folco") select(a))
}
Use CoC approach to
build relationship.
Squeryl
object Schema extends Schema{
! val foo = table[Foo]
! val bar = table[Bar]
! val fooToBar = oneToManyRelation(Foo, Bar).via(
! ! (f,b) => f.barId === b.id
! )
}
class Foo(var barId:Long) extends SomeEntity {
! lazy val bar:ManyToOne[Bar] = schema.fooToBar.right(this)
}
class Bar(var bar:String) extends SomeEntity {
! lazy val foos:OneToMany[Foo] = schema.fooToBar.left(this)
}
Use CoC approach to
build relationship.
Scala-ActiveRecord
object Table extends ActiveRecordTabels {
! val foo = table[Foo]
! val bar = table[Bar]
}
class Foo(var barId:Long) extends ActiveRecord {
! lazy val bar = belongsTo[Bar]
}
class Bar(var bar:String) extends ActiveRecord {
! lazy val foos = hasMany[Foo]
}
Getting Started
Define the dependency
in SBT project definition
Add the following settings in build.sbt or project/Build.scala.
libraryDependencies ++= Seq(
"com.github.aselab" %% "scala-activerecord" % "0.2.2",
"org.slf4j" % "slf4j-nop" % "1.7.2", // optional
"com.h2database" % "h2" % "1.3.170" // optional
)
resolvers += Resolver.sonatypeRepo("releases")
Using Scala ActiveRecord
Play2.1 Plugin
Add the following settings in project/Build.scala
val appDependencies = Seq(
"com.github.aselab" %% "scala-activerecord" % "0.2.2",
"com.github.aselab" %% "scala-activerecord-play2" % "0.2.2",
jdbc,
"com.h2database" % "h2" % "1.3.170"
)
val main = play.Project(appName, appVersion, appDependencies)
.settings(
resolvers ++= Seq(
Resolver.sonatypeRepo("releases")
)
)
Add the following settings in conf/play.plugins
9999:com.github.aselab.activerecord.ActiveRecordPlugin
Database Support
H2 database
MySQL
PostgrSQL
Derby
Oracle
Defining Schema
Model implementation
case class Person(var name:String, var age:Int)
! extends ActiveRecord
object Person
! extends ActiveRecordCompanion[Person]
Schema definition
object Tables extends ActiveRecordTable {
! val people = table[Person]
}
CRUD
Create
val person = Person("person1", 25)
person.save // return true
val person = Preson("person1", 25).create
// return Person("person1", 25)
Read
Person.find(1)
// Some(Person("person1"))
Person.toList
// List(person("person1”), ...)
Person.findBy("name", "john")
// Some(Person("John"))
Person.where(_.name === "john").headOption
// Some(Person("john"))
Update
Person.find(1).foreach { p =>
! p.name = "Ichiro"
! p.age = 37
! p.save
}
Person.forceUpdate( _.id === 1)(
! _.name := "ichiro", _.age := 37
)
Delete
Person.where(_.name === "john").foreach(_.delete)
Person.find(1) match {
! case Some(person) => person.delete
! case _ =>
}
Person.delete(1)
Query Interface
Find single object
val client = Client.find(10)
// Some(Client) or None
val John = Client.findBy("name", "john")
// Some(Client("john")) or None
val john = Client.findBy(("name", "john"), ("age",25))
// Some(Client("john",25)) or None
Get the search result as List
Scala
Clients.where(c =>
! c.name === "john" and c.age.~ > 25
).toList
Clients
! .where(_.name == "john")
! .where(_.age.~ > 25)
! .toList
generated SQL
select clients.name, clients.age, clients.id
from clients
where clients.name = "john" and clients.age > 25
Using iterable methods
val client = Client.head
// First Client or RecordNotFoundException
val client = Client.lastOption
// Some(Last Client) or None
val (adults, children) = Client.partition(_.age >= 20)
// Parts of clients
Ordering
Client.orderBy(_.name)
Client.orderBy(_.name asc)
Client.orderBy(_.name asc, _.age desc)
Limit
Client.limit(10)
Offset
Client.page(2, 5)
Existence
Client.exists(_.name like “john%”)
// true or false
Specify selected fields
Client.select(_.name).toList
// List[String]
Client.select(c => (c.name, c.age)).toList
// List[(String, Int)]
Combine Queries
Scala
Clients.where(_.name like "john%")
! .orderBy(_.age desc)
! .where(_.age.~ < 25)
! .page(2, 5)
! .toList
generated SQL
select clients.name, clients.age, clients.id
from clients
where ((clients.name like "john%") and (clients.age < 25))
order by clients.age desc
limit 5 offset 2
Cache Control
val orders = Order.where(_.age.~ > 20)
//execute this SQL query and cheche the query
orders.toList
//don't execute the SQL query
orders.toList
When the query is implicitly converted, the query is cached.
Validations
Annotation-based
Validation
case class User(
! @Required name:String,
! @Length(max=20) profile:String,
! @Range(min=0, max=150) age:Int
) extends ActiveRecord
Object User extends ActiveRecordCompanion[User]
Example
val user = user("", "Profile", 25).create
user.isValid // false
user.hasErrors // true
user.errors.messages // Seq("Name is required")
user.hasError("name") // true
User("", "profile", 15).saveEither match {
case Right(user) => println(user.name)
case Left(errors) => println(errors.message)
}
// "Name is required"
Callbacks
Available hooks
•beforeValidation
•beforeCreate
•afterCreate
•beforeUpdate
•afterUpdate
•beforeSave
•afterSave
•beforeDelete
•afterDelete
Example
case class User(login:String) extends ActiveRecord {
! @Transient
! var password:String = _
! var hashedPassword:String = _
! override def beforeSave() {
! ! hashedPassword = SomeLibrary.encrypt(password)
! }
}
val user = User("john")
user.password = "raw_password"
user.save
// stored encrypted password
Relationship
One-to-Many
case class User(name:String) extends ActiveRecord {
! val groupId:Option[Long] = None
! lazy val group = belongsTo[Group]
}
case class Group(name:String) extends ActiveRecord {
! lazy val users = hasMany[User]
}
groups
id
name
users
id
group_id
name
One-to-Many
val user1 = User("user1").create
val group1 = Group("group1").create
group1.users << user1
group1.users.toList
// List(User("user1"))
user1.group.getOrElse(Group("group2"))
// Group("group1")
Generated SQL sample
Scala
group1.users.where(_.name like "user%")
! .orderBy(_.id desc)
! .limit(5)
! .toList
generated SQL
Select users.name, users.id
From users
Where ((users.group_id = 1) And (users.name like "user%"))
Order by users.id Desc
limit 5 offset 0
Many-to-Many (HABTM)
case class User(name:String) extends ActiveRecord {
! lazy val groups = hasAndBelongsToMany[Group]
}
case class Group(name:String) extends ActiveRecord {
! lazy val users = hasAndBelongsToMany[user]
}
groups
id
name
groups_users
left_id
right_id
users
id
name
val user1 = User("user1").create
val group1 = Group("group1").create
val group2 = Group("group2").create
user1.groups := List(group1, group2)
user1.groups.toList
// List(Group("group1"), Group("group2"))
group1.users.toList
// List(User("user1"))
Many-to-Many (HABTM)
Many-to-Many
(hasManyThrough)
groups
id
name
memberships
id
user_id
group_id
isAdmin
users
id
name
Many-to-Many
(hasManyThrough)
case class Membership(
! userId:Long, projectid:Long, isAdmin:Boolean = false
) extends ActiveRecord {
! lazy val user = belongsTo[User]
! lazy val group = belongsTo[Group]
}
case class User(name:String) extends ActiveRecord {
! lazy val memberships = hasMany[Membership]
! lazy val groups = hasManyThrough[Group, Membership](memberships)
}
case class Group(name:String) extends ActiveRecord {
! lazy val memberships = hasmany[Membership]
! lazy val users = hasManyThrough[User, Membership](memberships)
}
Conditions Options
case class Group(name:String) extends ActiveRecord {
! lazy val adminUsers =
! ! hasMany[User](conditions = Map("isAdmin" -> true))
}
group.adminUsers << user
// user.isAdmin == true
ForeignKey option
case class Comment(name:String) extends ActiveRecord {
! val authorId:Long
! lazy val author
= belongsTo[User](foreignKey = "authorId")
}
Join Tables
Scala
Client.joins[Order](
! (client, order) => client.id === order.clientId
).where(
! (client, order) => client.age.~ < 20 and order.price.~ > 1000
).select(
! (client, order) => (client.name, client.age, order.price)
).toList
generated SQL
Select clients.name, clients.age, order.price
From clients inner join orders on (clients.id = orders.client_id)
Where ((clients.age < 20) and (groups.price > 1000))
Eager loading associations
The solution for N+1 problem.
Scala
Order.includes(_.client).limit(10).map {
! order => order.client.name
}.mkString("n")
generated SQL
Select orders.price, orders.id
From orders limit 10 offset 0
Select clients.name, clients.age, clients.id
From clients inner join orders on (clients.id = orders.client_id)
Where (orders.id in (1,2,3,4,5,6,7,8,9,10))
Logging and Debugging
See the generated SQLs
Use the toSql method
println(User.where(_.name like "john%").orderBy(_.age desc).toSql)
Set logging level with “debug” in logback.xml
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
In SBT console
build.sbt or project/Build.scala
initialCommands in console := """
import com.github.aselab.activerecord._
import com.github.aselab.activerecord.dsl._
import models._
SomeTables.initialize(Map("schema" -> "models.SomeTables"))
"""
In the console
> console
scala> User.forceInsertAll{ (1 to 10000).map{i => User("name" + i)} }
scala> User.where(_.name === "name10").toList
Testing
Setting for test
build.sbt or project/Build.scala
libraryDependencies ++= Seq(
"com.github.aselab" %% "scala-activerecord" % "0.2.2",
"com.github.aselab" %% "scala-activerecord-specs" % "0.2.2" % "test",
"org.specs2" %% "specs2" % "1.12.3" % "test"
)
resolvers += Resolver.sonatypeRepo("releases")
application.conf
test {
schema = "models.Tables"
driver = "org.h2.Driver"
jdbcurl = "jdbc:h2:mem:test"
}
Test Example
import com.github.aselab.activerecord._
object SomeModelSpecs extends ActiveRecordSpecification {
override val config
= Map("schema" -> "com.example.models.Tables")
override def beforeAll = {
super.beforeAll
SomeModel("test1").create
}
override def afterAll = {
super.afterAll
}
"sample" should {
// Some specifications code
}
}
Performance
ActiveRecord Overhead
• How Sql statements are generated.
• The time to create active-record object
from the results of query.
ORM Race
•Anorm
•Slick
•Squerl
•Scala-ActiveRecord
Race Condition
• Create the “User” table which has only 3 columns
• Insert 1000 records into the “User” table
• Select all from the table with same statements
• Time their trip to the end of creation objects
• Exclude the time to creating DB connection
• Use Play framework 2.1.1
• Use H2-database
• Run in Global.onStart
• Run 5 times
• Compare with the average times
The Racers
Anorm Squeryl
Slick Scala-ActiveRecord
SQL("SELECT * FROM USER")
.as(User.simple *)
Query(Users).list
from(AppDB.user)
(s => select(s))
.toList
User.all.toList
The Race Results
39.8ms
116.8ms
177.2ms
258.8ms
Squeryl
Anorm
Scala-ActiveRecord
Slick
Future
Validation at compiling
(with “Macro”)
• The findBy method and conditions of
association will be type-safe.
• Validate whether foreign-key is specified
with existing key or not.
Support Serialization
Form Model XML
JSON
MessagePack
Validation
View
Bind
View
Helper
Support Web framework
• CRUD controller
• Form Helper for Play and Scalatra
• Code generator as SBT plugin
Secret
DEMO withYATTER
(Yet Another twiTTER )
YATTER’s tables
Follows
id
userid
follows_users
id
user_id
follow_id
Users
id
name
Tweets
id
userId
textManyToMany
OneToMany
OneToOne
(But not supported yet)
https://github.com/ironpeace/yatter
#scalajp
Mt.FUJI
Tokyo Station
Japanese Castle
Sushi
Okonomiyaki
@teppei_tosa_en
https://github.com/aselab/scala-activerecord
https://github.com/ironpeace/yatter
Thank you

Más contenido relacionado

La actualidad más candente

Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaKazuhiro Sera
 
How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]Devon Bernard
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak SearchJustin Edelson
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/HibernateSunghyouk Bae
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghStuart Roebuck
 
DOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A RideDOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A RideMatthew McCullough
 
Java EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJava EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJiayun Zhou
 
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一scalaconfjp
 
Administering and Monitoring SolrCloud Clusters
Administering and Monitoring SolrCloud ClustersAdministering and Monitoring SolrCloud Clusters
Administering and Monitoring SolrCloud ClustersSematext Group, Inc.
 
Testing your javascript code with jasmine
Testing your javascript code with jasmineTesting your javascript code with jasmine
Testing your javascript code with jasmineRubyc Slides
 
First glance at Akka 2.0
First glance at Akka 2.0First glance at Akka 2.0
First glance at Akka 2.0Vasil Remeniuk
 
ScalaDays 2014 - Reactive Scala 3D Game Engine
ScalaDays 2014 - Reactive Scala 3D Game Engine ScalaDays 2014 - Reactive Scala 3D Game Engine
ScalaDays 2014 - Reactive Scala 3D Game Engine Aleksandar Prokopec
 
Advanced akka features
Advanced akka featuresAdvanced akka features
Advanced akka featuresGrzegorz Duda
 
Easy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMix
Easy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMixEasy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMix
Easy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMixelliando dias
 
Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)Yevgeniy Brikman
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code genkoji lin
 

La actualidad más candente (20)

Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in Scala
 
How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]How to Design a Great API (using flask) [ploneconf2017]
How to Design a Great API (using flask) [ploneconf2017]
 
Requery overview
Requery overviewRequery overview
Requery overview
 
Load Data Fast!
Load Data Fast!Load Data Fast!
Load Data Fast!
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak Search
 
Spring data requery
Spring data requerySpring data requery
Spring data requery
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/Hibernate
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
 
DOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A RideDOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A Ride
 
Java EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJava EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSF
 
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一
Building a Unified Data Pipline in Spark / Apache Sparkを用いたBig Dataパイプラインの統一
 
Administering and Monitoring SolrCloud Clusters
Administering and Monitoring SolrCloud ClustersAdministering and Monitoring SolrCloud Clusters
Administering and Monitoring SolrCloud Clusters
 
55 New Features in Java 7
55 New Features in Java 755 New Features in Java 7
55 New Features in Java 7
 
Testing your javascript code with jasmine
Testing your javascript code with jasmineTesting your javascript code with jasmine
Testing your javascript code with jasmine
 
First glance at Akka 2.0
First glance at Akka 2.0First glance at Akka 2.0
First glance at Akka 2.0
 
ScalaDays 2014 - Reactive Scala 3D Game Engine
ScalaDays 2014 - Reactive Scala 3D Game Engine ScalaDays 2014 - Reactive Scala 3D Game Engine
ScalaDays 2014 - Reactive Scala 3D Game Engine
 
Advanced akka features
Advanced akka featuresAdvanced akka features
Advanced akka features
 
Easy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMix
Easy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMixEasy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMix
Easy Enterprise Integration Patterns with Apache Camel, ActiveMQ and ServiceMix
 
Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code gen
 

Similar a Scala active record

Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrationstakezoe
 
Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scalascalaconfjp
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffJAX London
 
Spark Sql for Training
Spark Sql for TrainingSpark Sql for Training
Spark Sql for TrainingBryan Yang
 
Project kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scalaProject kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scalaSkills Matter Talks
 
Scala in a wild enterprise
Scala in a wild enterpriseScala in a wild enterprise
Scala in a wild enterpriseRafael Bagmanov
 
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em RubyTDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em RubyFabio Akita
 
Scala Italy 2015 - Hands On ScalaJS
Scala Italy 2015 - Hands On ScalaJSScala Italy 2015 - Hands On ScalaJS
Scala Italy 2015 - Hands On ScalaJSAlberto Paro
 
Alberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.jsAlberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.jsScala Italy
 
Using the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service ClientsUsing the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service ClientsSalesforce Developers
 
Alloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonAlloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonFokke Zandbergen
 
Rafael Bagmanov «Scala in a wild enterprise»
Rafael Bagmanov «Scala in a wild enterprise»Rafael Bagmanov «Scala in a wild enterprise»
Rafael Bagmanov «Scala in a wild enterprise»e-Legion
 
Real-time streaming and data pipelines with Apache Kafka
Real-time streaming and data pipelines with Apache KafkaReal-time streaming and data pipelines with Apache Kafka
Real-time streaming and data pipelines with Apache KafkaJoe Stein
 
Rails 3 (beta) Roundup
Rails 3 (beta) RoundupRails 3 (beta) Roundup
Rails 3 (beta) RoundupWayne Carter
 

Similar a Scala active record (20)

Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrations
 
Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scala
 
Lobos Introduction
Lobos IntroductionLobos Introduction
Lobos Introduction
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
 
Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
 
Spark Sql for Training
Spark Sql for TrainingSpark Sql for Training
Spark Sql for Training
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
 
Full Stack Scala
Full Stack ScalaFull Stack Scala
Full Stack Scala
 
Project kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scalaProject kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scala
 
Scala in a wild enterprise
Scala in a wild enterpriseScala in a wild enterprise
Scala in a wild enterprise
 
Jstl Guide
Jstl GuideJstl Guide
Jstl Guide
 
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em RubyTDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
 
Scala Italy 2015 - Hands On ScalaJS
Scala Italy 2015 - Hands On ScalaJSScala Italy 2015 - Hands On ScalaJS
Scala Italy 2015 - Hands On ScalaJS
 
Alberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.jsAlberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.js
 
Using the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service ClientsUsing the Tooling API to Generate Apex SOAP Web Service Clients
Using the Tooling API to Generate Apex SOAP Web Service Clients
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
Alloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonAlloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLon
 
Rafael Bagmanov «Scala in a wild enterprise»
Rafael Bagmanov «Scala in a wild enterprise»Rafael Bagmanov «Scala in a wild enterprise»
Rafael Bagmanov «Scala in a wild enterprise»
 
Real-time streaming and data pipelines with Apache Kafka
Real-time streaming and data pipelines with Apache KafkaReal-time streaming and data pipelines with Apache Kafka
Real-time streaming and data pipelines with Apache Kafka
 
Rails 3 (beta) Roundup
Rails 3 (beta) RoundupRails 3 (beta) Roundup
Rails 3 (beta) Roundup
 

Más de 鉄平 土佐

GraphX によるグラフ分析処理の実例と入門
GraphX によるグラフ分析処理の実例と入門GraphX によるグラフ分析処理の実例と入門
GraphX によるグラフ分析処理の実例と入門鉄平 土佐
 
Reactテストに役立つ実装の工夫
Reactテストに役立つ実装の工夫Reactテストに役立つ実装の工夫
Reactテストに役立つ実装の工夫鉄平 土佐
 
GraphX Advent Calendar Day17
GraphX Advent Calendar Day17GraphX Advent Calendar Day17
GraphX Advent Calendar Day17鉄平 土佐
 
GraphX Advent Calendar Day15
GraphX Advent Calendar Day15GraphX Advent Calendar Day15
GraphX Advent Calendar Day15鉄平 土佐
 
GraphX Advent Calendar Day 14
GraphX Advent Calendar Day 14GraphX Advent Calendar Day 14
GraphX Advent Calendar Day 14鉄平 土佐
 
GraphX Advent Calendar Day 13
GraphX Advent Calendar Day 13GraphX Advent Calendar Day 13
GraphX Advent Calendar Day 13鉄平 土佐
 
GraphX Advent Calendar Day12 : Pregel概要
GraphX Advent Calendar Day12 : Pregel概要GraphX Advent Calendar Day12 : Pregel概要
GraphX Advent Calendar Day12 : Pregel概要鉄平 土佐
 
Asakusa fwはじめの一歩 0.7.0
Asakusa fwはじめの一歩 0.7.0Asakusa fwはじめの一歩 0.7.0
Asakusa fwはじめの一歩 0.7.0鉄平 土佐
 
Spark GraphXについて @Spark Meetup 2014/9/8
Spark GraphXについて @Spark Meetup 2014/9/8Spark GraphXについて @Spark Meetup 2014/9/8
Spark GraphXについて @Spark Meetup 2014/9/8鉄平 土佐
 
「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1
「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1
「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1鉄平 土佐
 
GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014
GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014
GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014鉄平 土佐
 
GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014
GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014
GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014鉄平 土佐
 
Asakusa fw演算子チートシートについて
Asakusa fw演算子チートシートについてAsakusa fw演算子チートシートについて
Asakusa fw演算子チートシートについて鉄平 土佐
 
Asakusa fw勉強会2014真夏
Asakusa fw勉強会2014真夏Asakusa fw勉強会2014真夏
Asakusa fw勉強会2014真夏鉄平 土佐
 
Asakusa Framework 勉強会 2014 夏
Asakusa Framework 勉強会 2014 夏Asakusa Framework 勉強会 2014 夏
Asakusa Framework 勉強会 2014 夏鉄平 土佐
 
Asakusa Framework はじめの一歩 ( ver 0.6.2 )
Asakusa Framework はじめの一歩 ( ver 0.6.2 )Asakusa Framework はじめの一歩 ( ver 0.6.2 )
Asakusa Framework はじめの一歩 ( ver 0.6.2 )鉄平 土佐
 
Asakusa fwはじめの一歩・改
Asakusa fwはじめの一歩・改Asakusa fwはじめの一歩・改
Asakusa fwはじめの一歩・改鉄平 土佐
 
Asakusa fw勉強会2014冬
Asakusa fw勉強会2014冬Asakusa fw勉強会2014冬
Asakusa fw勉強会2014冬鉄平 土佐
 
Scala稟議の通し方(公開版)
Scala稟議の通し方(公開版)Scala稟議の通し方(公開版)
Scala稟議の通し方(公開版)鉄平 土佐
 

Más de 鉄平 土佐 (20)

GraphX によるグラフ分析処理の実例と入門
GraphX によるグラフ分析処理の実例と入門GraphX によるグラフ分析処理の実例と入門
GraphX によるグラフ分析処理の実例と入門
 
Reactテストに役立つ実装の工夫
Reactテストに役立つ実装の工夫Reactテストに役立つ実装の工夫
Reactテストに役立つ実装の工夫
 
GraphX Advent Calendar Day17
GraphX Advent Calendar Day17GraphX Advent Calendar Day17
GraphX Advent Calendar Day17
 
GraphX Advent Calendar Day15
GraphX Advent Calendar Day15GraphX Advent Calendar Day15
GraphX Advent Calendar Day15
 
GraphX Advent Calendar Day 14
GraphX Advent Calendar Day 14GraphX Advent Calendar Day 14
GraphX Advent Calendar Day 14
 
GraphX Advent Calendar Day 13
GraphX Advent Calendar Day 13GraphX Advent Calendar Day 13
GraphX Advent Calendar Day 13
 
GraphX Advent Calendar Day12 : Pregel概要
GraphX Advent Calendar Day12 : Pregel概要GraphX Advent Calendar Day12 : Pregel概要
GraphX Advent Calendar Day12 : Pregel概要
 
Asakusa fwはじめの一歩 0.7.0
Asakusa fwはじめの一歩 0.7.0Asakusa fwはじめの一歩 0.7.0
Asakusa fwはじめの一歩 0.7.0
 
Spark GraphXについて @Spark Meetup 2014/9/8
Spark GraphXについて @Spark Meetup 2014/9/8Spark GraphXについて @Spark Meetup 2014/9/8
Spark GraphXについて @Spark Meetup 2014/9/8
 
「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1
「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1
「Asakusa0.7の新機能で、テストデータをどうドキュメントするのか的な実用的なアレ」 by @okachimachiorz1
 
GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014
GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014
GraphXはScalaエンジニアにとってのブルーオーシャン @ Scala Matsuri 2014
 
GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014
GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014
GraphX is the blue ocean for scala engineers @ Scala Matsuri 2014
 
Asakusa fw演算子チートシートについて
Asakusa fw演算子チートシートについてAsakusa fw演算子チートシートについて
Asakusa fw演算子チートシートについて
 
Asakusa fw勉強会2014真夏
Asakusa fw勉強会2014真夏Asakusa fw勉強会2014真夏
Asakusa fw勉強会2014真夏
 
Asakusa Framework 勉強会 2014 夏
Asakusa Framework 勉強会 2014 夏Asakusa Framework 勉強会 2014 夏
Asakusa Framework 勉強会 2014 夏
 
Asakusa Framework はじめの一歩 ( ver 0.6.2 )
Asakusa Framework はじめの一歩 ( ver 0.6.2 )Asakusa Framework はじめの一歩 ( ver 0.6.2 )
Asakusa Framework はじめの一歩 ( ver 0.6.2 )
 
Asakusa fwはじめの一歩・改
Asakusa fwはじめの一歩・改Asakusa fwはじめの一歩・改
Asakusa fwはじめの一歩・改
 
Asakusa fw勉強会2014冬
Asakusa fw勉強会2014冬Asakusa fw勉強会2014冬
Asakusa fw勉強会2014冬
 
Scala稟議の通し方(公開版)
Scala稟議の通し方(公開版)Scala稟議の通し方(公開版)
Scala稟議の通し方(公開版)
 
はてブちう
はてブちうはてブちう
はてブちう
 

Último

Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 

Último (20)

Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 

Scala active record

  • 1. Scala-ActiveRecord Type-safe Active Record model for Scala @teppei_tosa_en
  • 2. Who am I 鉄平 土佐 TEPPEI TOSA iron peace place name
  • 3. The first official conference in Japan. http://scalaconf.jp/en/
  • 4. Typesafe members came to Japan and gave speeches.
  • 5. Talked about the case example of building our original BRMS “BIWARD” in Scala.
  • 6. Japanese engineers talked about Scala tips or their libraries. • “Stackable-controller” by @gakuzzzz https://github.com/t2v/stackable-controller • “How we write and use Scala libraries not to cry” by @tototoshi http://tototoshi.github.io/slides/how-we-write-and-use-scala-libraries- scalaconfjp2013/#1 For example, http://scalaconf.jp/en/
  • 7. Scala-ActiveRecord Type-safe Active Record model for Scala • https://github.com/aselab/scala-activerecord • Latest version : 0.2.2 • Licence : MIT
  • 8. Features • Squeryl wrapper • type-safe (most part) • Rails ActiveRecord-like operability • Auto transaction control • validations • Associations • Testing support
  • 9. Most of the other ORM Libraries Wrap SQL val selectCountries = SQL(“Select * from Countries”) Have to define mappings from the results of SQL to the models. val countries = selectCountries().map(row => row[String](“code”) -> row[String](“name”) ).toList
  • 10. The motivation of Scala-ActiveRecord • Want to define the model mapping more easily. • Want not to define the find methods in each model classes. • Want not to write SQLs.
  • 11. Other libraries example 1. Anorm 2. Slick ( ScalaQuery ) 3. Squeryl
  • 12. 1.Anorm • Anorm doesn’t have the Model layer. • Have to define similar methods in each Class. case class Person(id:Pk[Long], name:String) object Person { ! def create(person:Person):Unit = { ! ! DB.withConnection { implicit connection => ! ! ! SQL("insert int person(name) values ({name}") ! ! ! ! .on('name -> person.name) ! ! ! ! .executeUpdate() ! ! } ! } ! ... }
  • 13. 2. Slick ( ScalaQuery ) • Query Interface is good. • Definding tables syntax is redundant. • Have to define the mapping between table and model in each table. case class Member(id:Int, name:String, email:Option[String]) object Members extends Table[Member]("MEMBERS") { ! def id = column[Int]("ID", O.PrimaryKey, O.AutoInc) ! def name = column[String]("Name") ! def email = column[Option[String]]("EMAIL") ! def * = id.? ~ name ~ email <> (Member, Member.unapply _) }
  • 14. 3. Squeryl • The best one in these libraries. • Scala-ActiveRecord wraps this with some improvement. 1. Optimize the generated SQLs 2. Automate the transaction control 3. Use CoC approach to build relationship
  • 15. When queries are combined Squeryl generates sub-query SQL. Squeryl val query = from(table)(t => where(t.id.~ > 20) select(t)) from(query)(t => where(t.name like "%test%) select(t)) Scala select * from ! (Select * from table where table.id > 20) q1 where q1.name like "test" SQL It negatively affect performance.
  • 16. When queries are combined Squeryl generates sub-query SQL. Scala-ActiveRecord val query = Table.where(_.id.~ > 20) query.where(_.name like "%test%").toList Scala select * from table where table.id > 20 and table.name like "test" SQL It can generate more simple SQL statement.
  • 17. Automate the transaction control Squeryl Scala-ActiveRecord • Call “inTransaction” automatically at accessing Iterable#iterator. • When the save or delete method is called, “inTransaction” is executed by default. • Off course, you can call “inTransaction” expressly. inTransaction { books.insert(new Author(1, "Michel","Folco"))! ! val a = from(authors) (a=> where(a.lastName === "Folco") select(a)) }
  • 18. Use CoC approach to build relationship. Squeryl object Schema extends Schema{ ! val foo = table[Foo] ! val bar = table[Bar] ! val fooToBar = oneToManyRelation(Foo, Bar).via( ! ! (f,b) => f.barId === b.id ! ) } class Foo(var barId:Long) extends SomeEntity { ! lazy val bar:ManyToOne[Bar] = schema.fooToBar.right(this) } class Bar(var bar:String) extends SomeEntity { ! lazy val foos:OneToMany[Foo] = schema.fooToBar.left(this) }
  • 19. Use CoC approach to build relationship. Scala-ActiveRecord object Table extends ActiveRecordTabels { ! val foo = table[Foo] ! val bar = table[Bar] } class Foo(var barId:Long) extends ActiveRecord { ! lazy val bar = belongsTo[Bar] } class Bar(var bar:String) extends ActiveRecord { ! lazy val foos = hasMany[Foo] }
  • 21. Define the dependency in SBT project definition Add the following settings in build.sbt or project/Build.scala. libraryDependencies ++= Seq( "com.github.aselab" %% "scala-activerecord" % "0.2.2", "org.slf4j" % "slf4j-nop" % "1.7.2", // optional "com.h2database" % "h2" % "1.3.170" // optional ) resolvers += Resolver.sonatypeRepo("releases")
  • 22. Using Scala ActiveRecord Play2.1 Plugin Add the following settings in project/Build.scala val appDependencies = Seq( "com.github.aselab" %% "scala-activerecord" % "0.2.2", "com.github.aselab" %% "scala-activerecord-play2" % "0.2.2", jdbc, "com.h2database" % "h2" % "1.3.170" ) val main = play.Project(appName, appVersion, appDependencies) .settings( resolvers ++= Seq( Resolver.sonatypeRepo("releases") ) ) Add the following settings in conf/play.plugins 9999:com.github.aselab.activerecord.ActiveRecordPlugin
  • 25. Model implementation case class Person(var name:String, var age:Int) ! extends ActiveRecord object Person ! extends ActiveRecordCompanion[Person] Schema definition object Tables extends ActiveRecordTable { ! val people = table[Person] }
  • 26. CRUD
  • 27. Create val person = Person("person1", 25) person.save // return true val person = Preson("person1", 25).create // return Person("person1", 25)
  • 28. Read Person.find(1) // Some(Person("person1")) Person.toList // List(person("person1”), ...) Person.findBy("name", "john") // Some(Person("John")) Person.where(_.name === "john").headOption // Some(Person("john"))
  • 29. Update Person.find(1).foreach { p => ! p.name = "Ichiro" ! p.age = 37 ! p.save } Person.forceUpdate( _.id === 1)( ! _.name := "ichiro", _.age := 37 )
  • 30. Delete Person.where(_.name === "john").foreach(_.delete) Person.find(1) match { ! case Some(person) => person.delete ! case _ => } Person.delete(1)
  • 32. Find single object val client = Client.find(10) // Some(Client) or None val John = Client.findBy("name", "john") // Some(Client("john")) or None val john = Client.findBy(("name", "john"), ("age",25)) // Some(Client("john",25)) or None
  • 33. Get the search result as List Scala Clients.where(c => ! c.name === "john" and c.age.~ > 25 ).toList Clients ! .where(_.name == "john") ! .where(_.age.~ > 25) ! .toList generated SQL select clients.name, clients.age, clients.id from clients where clients.name = "john" and clients.age > 25
  • 34. Using iterable methods val client = Client.head // First Client or RecordNotFoundException val client = Client.lastOption // Some(Last Client) or None val (adults, children) = Client.partition(_.age >= 20) // Parts of clients
  • 37. Specify selected fields Client.select(_.name).toList // List[String] Client.select(c => (c.name, c.age)).toList // List[(String, Int)]
  • 38. Combine Queries Scala Clients.where(_.name like "john%") ! .orderBy(_.age desc) ! .where(_.age.~ < 25) ! .page(2, 5) ! .toList generated SQL select clients.name, clients.age, clients.id from clients where ((clients.name like "john%") and (clients.age < 25)) order by clients.age desc limit 5 offset 2
  • 39. Cache Control val orders = Order.where(_.age.~ > 20) //execute this SQL query and cheche the query orders.toList //don't execute the SQL query orders.toList When the query is implicitly converted, the query is cached.
  • 41. Annotation-based Validation case class User( ! @Required name:String, ! @Length(max=20) profile:String, ! @Range(min=0, max=150) age:Int ) extends ActiveRecord Object User extends ActiveRecordCompanion[User]
  • 42. Example val user = user("", "Profile", 25).create user.isValid // false user.hasErrors // true user.errors.messages // Seq("Name is required") user.hasError("name") // true User("", "profile", 15).saveEither match { case Right(user) => println(user.name) case Left(errors) => println(errors.message) } // "Name is required"
  • 45. Example case class User(login:String) extends ActiveRecord { ! @Transient ! var password:String = _ ! var hashedPassword:String = _ ! override def beforeSave() { ! ! hashedPassword = SomeLibrary.encrypt(password) ! } } val user = User("john") user.password = "raw_password" user.save // stored encrypted password
  • 47. One-to-Many case class User(name:String) extends ActiveRecord { ! val groupId:Option[Long] = None ! lazy val group = belongsTo[Group] } case class Group(name:String) extends ActiveRecord { ! lazy val users = hasMany[User] } groups id name users id group_id name
  • 48. One-to-Many val user1 = User("user1").create val group1 = Group("group1").create group1.users << user1 group1.users.toList // List(User("user1")) user1.group.getOrElse(Group("group2")) // Group("group1")
  • 49. Generated SQL sample Scala group1.users.where(_.name like "user%") ! .orderBy(_.id desc) ! .limit(5) ! .toList generated SQL Select users.name, users.id From users Where ((users.group_id = 1) And (users.name like "user%")) Order by users.id Desc limit 5 offset 0
  • 50. Many-to-Many (HABTM) case class User(name:String) extends ActiveRecord { ! lazy val groups = hasAndBelongsToMany[Group] } case class Group(name:String) extends ActiveRecord { ! lazy val users = hasAndBelongsToMany[user] } groups id name groups_users left_id right_id users id name
  • 51. val user1 = User("user1").create val group1 = Group("group1").create val group2 = Group("group2").create user1.groups := List(group1, group2) user1.groups.toList // List(Group("group1"), Group("group2")) group1.users.toList // List(User("user1")) Many-to-Many (HABTM)
  • 53. Many-to-Many (hasManyThrough) case class Membership( ! userId:Long, projectid:Long, isAdmin:Boolean = false ) extends ActiveRecord { ! lazy val user = belongsTo[User] ! lazy val group = belongsTo[Group] } case class User(name:String) extends ActiveRecord { ! lazy val memberships = hasMany[Membership] ! lazy val groups = hasManyThrough[Group, Membership](memberships) } case class Group(name:String) extends ActiveRecord { ! lazy val memberships = hasmany[Membership] ! lazy val users = hasManyThrough[User, Membership](memberships) }
  • 54. Conditions Options case class Group(name:String) extends ActiveRecord { ! lazy val adminUsers = ! ! hasMany[User](conditions = Map("isAdmin" -> true)) } group.adminUsers << user // user.isAdmin == true
  • 55. ForeignKey option case class Comment(name:String) extends ActiveRecord { ! val authorId:Long ! lazy val author = belongsTo[User](foreignKey = "authorId") }
  • 56. Join Tables Scala Client.joins[Order]( ! (client, order) => client.id === order.clientId ).where( ! (client, order) => client.age.~ < 20 and order.price.~ > 1000 ).select( ! (client, order) => (client.name, client.age, order.price) ).toList generated SQL Select clients.name, clients.age, order.price From clients inner join orders on (clients.id = orders.client_id) Where ((clients.age < 20) and (groups.price > 1000))
  • 57. Eager loading associations The solution for N+1 problem. Scala Order.includes(_.client).limit(10).map { ! order => order.client.name }.mkString("n") generated SQL Select orders.price, orders.id From orders limit 10 offset 0 Select clients.name, clients.age, clients.id From clients inner join orders on (clients.id = orders.client_id) Where (orders.id in (1,2,3,4,5,6,7,8,9,10))
  • 59. See the generated SQLs Use the toSql method println(User.where(_.name like "john%").orderBy(_.age desc).toSql) Set logging level with “debug” in logback.xml <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration>
  • 60. In SBT console build.sbt or project/Build.scala initialCommands in console := """ import com.github.aselab.activerecord._ import com.github.aselab.activerecord.dsl._ import models._ SomeTables.initialize(Map("schema" -> "models.SomeTables")) """ In the console > console scala> User.forceInsertAll{ (1 to 10000).map{i => User("name" + i)} } scala> User.where(_.name === "name10").toList
  • 62. Setting for test build.sbt or project/Build.scala libraryDependencies ++= Seq( "com.github.aselab" %% "scala-activerecord" % "0.2.2", "com.github.aselab" %% "scala-activerecord-specs" % "0.2.2" % "test", "org.specs2" %% "specs2" % "1.12.3" % "test" ) resolvers += Resolver.sonatypeRepo("releases") application.conf test { schema = "models.Tables" driver = "org.h2.Driver" jdbcurl = "jdbc:h2:mem:test" }
  • 63. Test Example import com.github.aselab.activerecord._ object SomeModelSpecs extends ActiveRecordSpecification { override val config = Map("schema" -> "com.example.models.Tables") override def beforeAll = { super.beforeAll SomeModel("test1").create } override def afterAll = { super.afterAll } "sample" should { // Some specifications code } }
  • 65. ActiveRecord Overhead • How Sql statements are generated. • The time to create active-record object from the results of query.
  • 67. Race Condition • Create the “User” table which has only 3 columns • Insert 1000 records into the “User” table • Select all from the table with same statements • Time their trip to the end of creation objects • Exclude the time to creating DB connection • Use Play framework 2.1.1 • Use H2-database • Run in Global.onStart • Run 5 times • Compare with the average times
  • 68. The Racers Anorm Squeryl Slick Scala-ActiveRecord SQL("SELECT * FROM USER") .as(User.simple *) Query(Users).list from(AppDB.user) (s => select(s)) .toList User.all.toList
  • 71. Validation at compiling (with “Macro”) • The findBy method and conditions of association will be type-safe. • Validate whether foreign-key is specified with existing key or not.
  • 72. Support Serialization Form Model XML JSON MessagePack Validation View Bind View Helper
  • 73. Support Web framework • CRUD controller • Form Helper for Play and Scalatra • Code generator as SBT plugin
  • 76.
  • 82. Sushi