SlideShare a Scribd company logo
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 )
Scala active record
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
Ad

More Related Content

What's hot (20)

Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in Scala
Kazuhiro 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
 
Requery overview
Requery overviewRequery overview
Requery overview
Sunghyouk Bae
 
Load Data Fast!
Load Data Fast!Load Data Fast!
Load Data Fast!
Karwin Software Solutions LLC
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak Search
Justin Edelson
 
Spring data requery
Spring data requerySpring data requery
Spring data requery
Sunghyouk Bae
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/Hibernate
Sunghyouk Bae
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
Stuart 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 Ride
Matthew 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 & JSF
Jiayun 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 Clusters
Sematext Group, Inc.
 
55 New Features in Java 7
55 New Features in Java 755 New Features in Java 7
55 New Features in Java 7
Boulder Java User's Group
 
Testing your javascript code with jasmine
Testing your javascript code with jasmineTesting your javascript code with jasmine
Testing your javascript code with jasmine
Rubyc Slides
 
First glance at Akka 2.0
First glance at Akka 2.0First glance at Akka 2.0
First glance at Akka 2.0
Vasil 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 features
Grzegorz 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 ServiceMix
elliando 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 gen
koji lin
 
Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in Scala
Kazuhiro 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 Search
Justin Edelson
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/Hibernate
Sunghyouk Bae
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
Stuart 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 Ride
Matthew 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 & JSF
Jiayun 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 Clusters
Sematext Group, Inc.
 
Testing your javascript code with jasmine
Testing your javascript code with jasmineTesting your javascript code with jasmine
Testing your javascript code with jasmine
Rubyc Slides
 
First glance at Akka 2.0
First glance at Akka 2.0First glance at Akka 2.0
First glance at Akka 2.0
Vasil 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 features
Grzegorz 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 ServiceMix
elliando 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 gen
koji lin
 

Similar to Scala active record (20)

Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrations
takezoe
 
Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scala
scalaconfjp
 
Lobos Introduction
Lobos IntroductionLobos Introduction
Lobos Introduction
Nicolas Buduroi
 
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
JAX London
 
Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
Eberhard Wolff
 
Spark Sql for Training
Spark Sql for TrainingSpark Sql for Training
Spark Sql for Training
Bryan Yang
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
Raimonds Simanovskis
 
Full Stack Scala
Full Stack ScalaFull Stack Scala
Full Stack Scala
Ramnivas Laddad
 
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
Skills Matter Talks
 
Scala in a wild enterprise
Scala in a wild enterpriseScala in a wild enterprise
Scala in a wild enterprise
Rafael Bagmanov
 
Jstl Guide
Jstl GuideJstl Guide
Jstl Guide
Yuval Zilberstein
 
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
Fabio Akita
 
Alberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.jsAlberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.js
Scala Italy
 
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
 
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
Salesforce Developers
 
Wider than rails
Wider than railsWider than rails
Wider than rails
Alexey Nayden
 
Alloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonAlloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLon
Fokke 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 Kafka
Joe Stein
 
Rails 3 (beta) Roundup
Rails 3 (beta) RoundupRails 3 (beta) Roundup
Rails 3 (beta) Roundup
Wayne Carter
 
Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrations
takezoe
 
Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scala
scalaconfjp
 
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
JAX London
 
Spark Sql for Training
Spark Sql for TrainingSpark Sql for Training
Spark Sql for Training
Bryan 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 scala
Skills Matter Talks
 
Scala in a wild enterprise
Scala in a wild enterpriseScala in a wild enterprise
Scala in a wild enterprise
Rafael 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 Ruby
Fabio Akita
 
Alberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.jsAlberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.js
Scala Italy
 
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
 
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
Salesforce Developers
 
Alloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonAlloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLon
Fokke 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 Kafka
Joe Stein
 
Rails 3 (beta) Roundup
Rails 3 (beta) RoundupRails 3 (beta) Roundup
Rails 3 (beta) Roundup
Wayne Carter
 
Ad

More from 鉄平 土佐 (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稟議の通し方(公開版)
鉄平 土佐
 
はてブちう
はてブちうはてブちう
はてブちう
鉄平 土佐
 
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稟議の通し方(公開版)
鉄平 土佐
 
Ad

Recently uploaded (20)

Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx
Samuele Fogagnolo
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Impelsys Inc.
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
Procurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptxProcurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptx
Jon Hansen
 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
 
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptxSpecial Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
shyamraj55
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
HCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser EnvironmentsHCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser Environments
panagenda
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx
Samuele Fogagnolo
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Enhancing ICU Intelligence: How Our Functional Testing Enabled a Healthcare I...
Impelsys Inc.
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
Procurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptxProcurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptx
Jon Hansen
 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
 
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptxSpecial Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
shyamraj55
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
HCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser EnvironmentsHCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser Environments
panagenda
 

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
  • 82. Sushi