SlideShare ist ein Scribd-Unternehmen logo
1 von 63
Downloaden Sie, um offline zu lesen
H E R D I NG { T Y P E S }
WITH SCALA #MACROS
Marina Sigaeva
ROADMAP
ROADMAP
▸ How Java driver stores
data in Aerospike
ROADMAP
▸ How Java driver stores
data in Aerospike
▸ What driver has to do
ROADMAP
▸ How Java driver stores
data in Aerospike
▸ What driver has to do
▸ The type safe solution
with Scala macros
KEY META
BINS
K1 (id,“Bob”)
K2 Bin1, Bin2, .. BinN
PEOPLE
NS1
SET:
KEY META
BINS
K1 (id,“Joe”)
K2 Bin1, Bin2, .. BinN
NS1
SET: PEOPLE
KEY META
BINS
K1 (id,1234)
K2 Bin1, Bin2, .. BinN
NS1
SET: PEOPLE
DS
DS DS
DS DS DS
Java
object DBConnector {



val config = ConfigFactory.load()



val hosts = List(config.getString("aerospike.host"))

val port = config.getInt("aerospike.port")

val namespace = config.getString("aerospike.namespace")

val setName = config.getString("aerospike.setName")



val database: AsyncClient = new AsyncClient(new AsyncClientPolicy, hosts.map(new Host(_, port)): _*)



val key1 = new Key("namespace", "setName", new StringValue("key1"))

val key2 = new Key("namespace", "setName", new StringValue("key2"))

val key3 = new Key("namespace", "setName", new StringValue("key3"))



database.put(new WritePolicy, key1, Seq(new Bin("bin1", new StringValue("abcd"))): _*) 

database.put(new WritePolicy, key2, Seq(new Bin("bin2", new IntegerValue(2))): _*) 

database.put(new WritePolicy, key3, Seq(new Bin("bin3", new BooleanValue(true))): _*) 



val record1 = database.get(new BatchPolicy, key1)

val record2 = database.get(new BatchPolicy, key2)

val record3 = database.get(new BatchPolicy, key3)



val res1 = longParsingFunction(record1)

val res2 = longParsingFunction(record2)

val res3 = longParsingFunction(record3)



def longParsingFunction[T](record: Record): T = {

val outValue: Map[String, Option[$tpe]] = {

val jMap = record.bins.view collect {

case (name, bt: Any) =>

val res = fetch(bt)



if (res.isEmpty && r.bins.nonEmpty) throw new Exception("Wrong type!")

else name -> res

Scalaobject DBConnector {



val db = new Database()



db.put("key1", "bin1", "abcd")

db.put("key2", "bin2", 2)

db.put("key3", "bin3", true) 



val res1 = db.get[String]("key1")

val res2 = db.get[Int]("key2")

val res3 = db.get[Boolean]("key3")

}
Part 1
data storing
package ru.tinkoff.example





object DBConnector {

…



database.put(new WritePolicy,

new Key("namespace", "setName", new StringValue("key1")),

Seq(new Bin("binName1", new StringValue("binValue"))):_*)



database.put(new WritePolicy,

new Key("namespace", "setName", new StringValue("key2")),

Seq(new Bin("binName2", new IntegerValue(2))):_*)



database.put(new WritePolicy,

new Key("namespace", "setName", new StringValue("key3")),

Seq(new Bin("binName3", new BooleanValue(true))):_*)



}
7 Key types
12 Bin types
db.put("key1", "bin1", "abcd")



db.put("key2", "bin2", 8)



db.put("key3", "bin3", true)



db.put("key4", "bin4", List(1.8, 33.8, 128))
db.put("key4", "bin4", List(true, false))
db.put("key5", "cat", Cat("Rex", 2))



db.put("key6", "trucks", 

List(Truck("F1", 8), Truck("F2", 23), 

Truck("F3", 11)))



db.put("key7", "students",

List(Student("Jack Green", A), 

Student("Sara Lee", A),

Student("Cameron Roonie", B)))

db.put("key8", "hList”",
"qwerty" :: 2 :: false :: HNil)
db.put("key5", "cat", Cat("Rex", 2))



db.put("key6", "trucks", 

List(Truck("F1", 8), Truck("F2", 23), 

Truck("F3", 11)))



db.put("key7", "students",

List(Student("Jack Green", A), 

Student("Sara Lee", A),

Student("Cameron Roonie", B)))

db.put("key8", "hList”",
"qwerty" :: 2 :: false :: HNil)
UNLIMITED
Boolean
Short
ByteInt
Long
H
List
Caseclass
Map
val hList = 123 :: "abcdef" :: true :: HNil
+———————————————————————-+
| hList |
+———————————————————————-+
| MAP('{"0":123, "1":"abcdef", "2":1}') |
+———————————————————————-+
val cat0 = Cat("Lewis", 3)
+—————————————————————-—-+
| cat0 |
+———————————————————————+
| MAP('{"name":"Lewis", "age":3}') |
+———————————————————————+
Part 2
getting data
get(policy: BatchPolicy, listener: BatchSequenceListener, records: util.List[Ba
get(policy: BatchPolicy, listener: RecordSequenceListener, keys: Array[Key], b
get(policy: BatchPolicy, listener: RecordArrayListener, keys: Array[Key], binN
get(policy: BatchPolicy, listener: RecordSequenceListener, keys: Array[Key])
get(policy: BatchPolicy, listener: RecordArrayListener, keys: Array[Key])

get(policy: Policy, listener: RecordListener, key: Key, binNames: String *)

get(policy: Policy, listener: RecordListener, key: Key)

get(policy: BatchPolicy, listener: BatchListListener, records: util.List[BatchRe
get(policy: BatchPolicy, records: util.List[BatchRead])

get(policy: BatchPolicy, keys: Array[Key], binNames: String *)

get(policy: BatchPolicy, keys: Array[Key])

get(policy: Policy, key: Key, binNames: String *)

get(policy: Policy, key: Key)
m
m
m
m
m
m
m
m
m
m
m
m
m
13
13
methods
public final class Record {

//Map of requested name/value bins.



public final Map<String,Object> bins;



public final int generation;

	 

public final int expiration;



…



}
val results = database.get(new BatchPolicy(), 

new RecordArrayListener(),

List("Lewis", "Mona", "Rex")

.map(key => createKey(key)))

.map(record => 

longParsingCatFunction(record))





def longParsingCatFunction[T](

record: Record): Option[T] = {





… 



}
db.get[List[Cat]](List("Lewis", "Mona", "Rex"))
WHAT DOES THE DRIVER
HAVE TO DO?
WHAT DOES THE DRIVER
HAVE TO DO?
▸ More concise API
WHAT DOES THE DRIVER
HAVE TO DO?
▸ More concise API
▸ Take care of serialization
WHAT DOES THE DRIVER
HAVE TO DO?
▸ More concise API
▸ Take care of serialization
▸ To work out of the box
Part 3
implementation
def call[K, B](action: Action, key: K, bin: B)

(implicit kw: KeyWrapper[K],

bw: BinWrapper[B],

pw: Option[WritePolicy] = None) = ???
def call[K, B](action: Action, key: K, bin: B)

(implicit kw: KeyWrapper[K],

bw: BinWrapper[B],

pw: Option[WritePolicy] = None) = ???
call(Put, “key”, “abcd”)
def call[K, B](action: Action, key: K, bin: B)

(implicit kw: KeyWrapper[K],

bw: BinWrapper[B],

pw: Option[WritePolicy] = None) = ???
call(Put, “key”, “abcd”)(
new KeyWrapper[String]{},

new BinWrapper[String]{}, None)
def call[K, B](action: Action, key: K, bin: B)

(implicit kw: KeyWrapper[K],

bw: BinWrapper[B],

pw: Option[WritePolicy] = None) = ???
def put[K, B](key: K, bin: B)(call(Put, key, bin))





def get[K, B](key: K)(call(Get, key))
trait KeyWrapper[K] {

def apply(k: K): Key = new Key(toValue(k))
def toValue(v: K): Value = v match {

case s: String => new StringValue(s)

case h: HList => new MapValue(toMap(h))

…

}

}
new KeyWrapper[String] {

def apply(k: String): Key = ???

} 



new KeyWrapper[HList] {

def apply(k: HList): Key = ???

}
new KeyWrapper[ ] {

def apply(k: ): Key = ???

}
new KeyWrapper[ ] {

def apply(k: ): Key = ???

}
Macros
Context
Symbol Type Tree
import c.universe._



Apply(

Select(Literal(Constant(1)), TermName("$plus")), 

List(Literal(Constant(1)))

)
1 + 1
import c.universe._



Apply(

Select(Literal(Constant(1)), TermName("$plus")), 

List(Literal(Constant(1)))

)
1 + 1
q"1 + 1"
object KeyWrapper {



implicit def materialize[K]: KeyWrapper[K] = macro implKey[K]



def implKey[K: c.WeakTypeTag](c: Context): c.Expr[KeyWrapper[K]] = {

import c.universe._

val tpe = weakTypeOf[K]
val imports = q""" 

import com.aerospike.client.{Key, Value} """



c.Expr[KeyWrapper[K]] {

q""" 

$imports

new KeyWrapper[$tpe] {}

"""

}

}

}
object KeyWrapper {



implicit def materialize[K]: KeyWrapper[K] = macro implKey[K]



def implKey[K: c.WeakTypeTag](c: Context): c.Expr[KeyWrapper[K]] = {

import c.universe._

val tpe = weakTypeOf[K]
val imports = q""" 

import com.aerospike.client.{Key, Value} """



c.Expr[KeyWrapper[K]] {

q""" 

$imports

new KeyWrapper[$tpe] {}

"""

}

}

}
object KeyWrapper {



implicit def materialize[K]: KeyWrapper[K] = macro implKey[K]



def implKey[K: c.WeakTypeTag](c: Context): c.Expr[KeyWrapper[K]] = {

import c.universe._

val tpe = weakTypeOf[K]
val imports = q""" 

import com.aerospike.client.{Key, Value} """



c.Expr[KeyWrapper[K]] {

q""" 

$imports

new KeyWrapper[$tpe] {}

"""

}

}

}
object Usage {

insertData(materialize[String])

}
object Usage {



insertData({

import com.aerospike.client.{Key, Value};

{
final class $anon extends KeyWrapper[String] {
def <init>() = {
super.<init>();
()
};
<empty>
};
new $anon()
}
})
}
new KeyWrapper[String]
new KeyWrapper[Int]
new KeyWrapper[HList]
new KeyWrapper[Cat]
trait BinWrapper[B] {
def apply(v: B): Bin = new Bin("name", toValue(v))
def toValue(v: B): Value = v match {
case s: String => new StringValue(s)
case h: HList => new MapValue(toMap(h))
case _ => throw new Exception("Wrong type")
}
def apply(r: Record): Map[String, B] =
r.bins.collect {
case (name, something) =>
name -> fetch(something)
}.toMap
def fetch(donkey: Any): B
}
trait BinWrapper[B] {
def apply(v: B): Bin = new Bin("name", toValue(v))
def toValue(v: B): Value = v match {
case s: String => new StringValue(s)
case h: HList => new MapValue(toMap(h))
case _ => throw new Exception("Wrong type")
}
def apply(r: Record): Map[String, B] =
r.bins.collect {
case (name, something) =>
name -> fetch(something)
}.toMap
def fetch(donkey: Any): B
}
object BinWrapper {



implicit def materialize[T]: BinWrapper[T] = macro matBin[T]



def matBin[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[BinWrapper[T]] = {

import c.universe._



val tpe = weakTypeOf[T]



val imports = q""" import …"""
val fetchValue = ???


c.Expr[BinWrapper[T]] {

q""" $imports

new BinWrapper[$tpe] { 

$fetchValue 

}""" 

}

}

}
object BinWrapper {



implicit def materialize[T]: BinWrapper[T] = macro matBin[T]



def matBin[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[BinWrapper[T]] = {

import c.universe._



val tpe = weakTypeOf[T]



val imports = q""" import …"""
val fetchValue = ???


c.Expr[BinWrapper[T]] {

q""" $imports

new BinWrapper[$tpe] { 

$fetchValue 

}""" 

}

}

}
val tpe = weakTypeOf[T]



val fetchValue = tpe match {
case t if t =:= weakTypeOf[String] =>
q""" def fetch(any: Any): $tpe = any match {
case v: String => v
case _ => throw new Exception("Wrong type")
} """
case t if isHList(t) =>
q""" def fetch(any: Any): $tpe = any match {
case mv: MapValue => mv.getObject match {
case m: Map[String, Any] =>
parse(m).toHList[$tpe].getOrElse{}
case _ => throw new Exception("Wrong type")
}
case _ => throw new Exception("Wrong type")
} """

...
}
Expr[ru.tinkoff.BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]]]({
import com.aerospike.client.{Key, Value};
import collection.JavaConversions._;
import com.aerospike.client.Value._;
import shapeless._;
import syntax.std.traversable._;
{
final class $anon extends BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] {
def <init>() = {
super.<init>();
()
};
def fetch(any: Any): shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]] = any match {
case (mv @ (_: MapValue)) => mv.getObject match {
case (m @ (_: Map[String, Any])) =>
parse(m).toHList[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]].getOrElse{}
case _ => throw new Exception("Wrong type")
}
case _ => throw new Exception("Wrong type")
}
};
new $anon()
}
})
BinWrapper.matBin[Int::Boolean::HNil]
Expr[ru.tinkoff.BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]]]({
import com.aerospike.client.{Key, Value};
import collection.JavaConversions._;
import com.aerospike.client.Value._;
import shapeless._;
import syntax.std.traversable._;
{
final class $anon extends BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] {
def <init>() = {
super.<init>();
()
};
def fetch(any: Any): shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]] = any match {
case (mv @ (_: MapValue)) => mv.getObject match {
case (m @ (_: Map[String, Any])) =>
parse(m).toHList[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]].getOrElse{}
case _ => throw new Exception("Wrong type")
}
case _ => throw new Exception("Wrong type")
}
};
new $anon()
}
})
}imports
def fetch: Any => HL
type HL = Int::Boolean::HNil
def writeBin[B](b: B)

(implicit bw: BinWrapper[B]): Bin = bw(b)





val asMap = new BinWrapper[Truck] { }

val asJson = new BinWrapper[Truck] { … }



writeBin("tr1", Truck("truck1", 4,

List(1, 2, 3)))(asMap)

writeBin("tr2", Truck("truck2", 2,

List(7, 8, 9)))(asJson)
PS: additional features
+ pitfalls
case class Sample(name: String, i: Int)



db.put("intKey", "intBin", 202))



db.put("hListKey", "hListBin",

"abcd" :: 2 :: 3 :: HNil))



db.put("mapKey", "mapBin",

Map(Sample("t1", 3) -> "v1",

Sample("t2", 2) -> "v2",

Sample("t3", 1) -> "v3")))
AQL > select * from test.test
[
{
"mapBin": {}
},
{
"intBin": 202
},
{
"hListBin": {
"0": "abcd",
"1": 2,
"2": 3
}
}
object CleanUp extends App {



val keys = List("mapKey", "intKey", "hListKey")



val res = Future.traverse(keys)(db.delete)

}
object CleanUp extends App {



val keys = List("mapKey", "intKey", "hListKey")



val res = Future.traverse(keys)(db.delete)

}
aql> select * from test.test
[
]
aerospike-scala-dsl
https://github.com/DanyMariaLee/aerospike-scala
"ru.tinkoff" % "aerospike-scala" % "1.1.14",

"ru.tinkoff" % "aerospike-scala-proto" % "1.1.14",

"ru.tinkoff" % "aerospike-scala-example" % "1.1.14"
CONTACT ME
besselfunction@mail.ru
@besseifunction
DanyMariaLee
@besselfunction
Herding types with Scala macros

Weitere ähnliche Inhalte

Was ist angesagt?

Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)MongoSF
 
Swift Sequences & Collections
Swift Sequences & CollectionsSwift Sequences & Collections
Swift Sequences & CollectionsCocoaHeads France
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196Mahmoud Samir Fayed
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event LoopDesignveloper
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemSages
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189Mahmoud Samir Fayed
 
Aggregation in MongoDB
Aggregation in MongoDBAggregation in MongoDB
Aggregation in MongoDBKishor Parkhe
 
Rのスコープとフレームと環境と
Rのスコープとフレームと環境とRのスコープとフレームと環境と
Rのスコープとフレームと環境とTakeshi Arabiki
 
Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察Tsuyoshi Yamamoto
 
Cycle.js: Functional and Reactive
Cycle.js: Functional and ReactiveCycle.js: Functional and Reactive
Cycle.js: Functional and ReactiveEugene Zharkov
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeMongoDB
 
Rデバッグあれこれ
RデバッグあれこれRデバッグあれこれ
RデバッグあれこれTakeshi Arabiki
 
Mozilla とブラウザゲーム
Mozilla とブラウザゲームMozilla とブラウザゲーム
Mozilla とブラウザゲームNoritada Shimizu
 

Was ist angesagt? (20)

Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
 
Swift Sequences & Collections
Swift Sequences & CollectionsSwift Sequences & Collections
Swift Sequences & Collections
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event Loop
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189
 
Aggregation in MongoDB
Aggregation in MongoDBAggregation in MongoDB
Aggregation in MongoDB
 
Rのスコープとフレームと環境と
Rのスコープとフレームと環境とRのスコープとフレームと環境と
Rのスコープとフレームと環境と
 
Elm: give it a try
Elm: give it a tryElm: give it a try
Elm: give it a try
 
Hw09 Hadoop + Clojure
Hw09   Hadoop + ClojureHw09   Hadoop + Clojure
Hw09 Hadoop + Clojure
 
Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察Jggug 2010 330 Grails 1.3 観察
Jggug 2010 330 Grails 1.3 観察
 
Python GC
Python GCPython GC
Python GC
 
Cycle.js: Functional and Reactive
Cycle.js: Functional and ReactiveCycle.js: Functional and Reactive
Cycle.js: Functional and Reactive
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
Rデバッグあれこれ
RデバッグあれこれRデバッグあれこれ
Rデバッグあれこれ
 
Hadoop + Clojure
Hadoop + ClojureHadoop + Clojure
Hadoop + Clojure
 
はじめてのGroovy
はじめてのGroovyはじめてのGroovy
はじめてのGroovy
 
Mozilla とブラウザゲーム
Mozilla とブラウザゲームMozilla とブラウザゲーム
Mozilla とブラウザゲーム
 
Angular Refactoring in Real World
Angular Refactoring in Real WorldAngular Refactoring in Real World
Angular Refactoring in Real World
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 

Ähnlich wie Herding types with Scala macros

MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012Amazon Web Services
 
San Francisco Java User Group
San Francisco Java User GroupSan Francisco Java User Group
San Francisco Java User Groupkchodorow
 
Getting Started with MongoDB and NodeJS
Getting Started with MongoDB and NodeJSGetting Started with MongoDB and NodeJS
Getting Started with MongoDB and NodeJSMongoDB
 
Un dsl pour ma base de données
Un dsl pour ma base de donnéesUn dsl pour ma base de données
Un dsl pour ma base de donnéesRomain Lecomte
 
GR8Conf 2011: Effective Groovy
GR8Conf 2011: Effective GroovyGR8Conf 2011: Effective Groovy
GR8Conf 2011: Effective GroovyGR8Conf
 
solving little problems
solving little problemssolving little problems
solving little problemsAustin Ziegler
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript IntroductionDmitry Sheiko
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETTomas Jansson
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 SpringKiyotaka Oku
 
Metaprogramming in Haskell
Metaprogramming in HaskellMetaprogramming in Haskell
Metaprogramming in HaskellHiromi Ishii
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages VictorSzoltysek
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門Tsuyoshi Yamamoto
 
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017 Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017 Codemotion
 
Writing native bindings to node.js in C++
Writing native bindings to node.js in C++Writing native bindings to node.js in C++
Writing native bindings to node.js in C++nsm.nikhil
 
Javascript development done right
Javascript development done rightJavascript development done right
Javascript development done rightPawel Szulc
 

Ähnlich wie Herding types with Scala macros (20)

MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
 
San Francisco Java User Group
San Francisco Java User GroupSan Francisco Java User Group
San Francisco Java User Group
 
Getting Started with MongoDB and NodeJS
Getting Started with MongoDB and NodeJSGetting Started with MongoDB and NodeJS
Getting Started with MongoDB and NodeJS
 
Un dsl pour ma base de données
Un dsl pour ma base de donnéesUn dsl pour ma base de données
Un dsl pour ma base de données
 
GR8Conf 2011: Effective Groovy
GR8Conf 2011: Effective GroovyGR8Conf 2011: Effective Groovy
GR8Conf 2011: Effective Groovy
 
Latinoware
LatinowareLatinoware
Latinoware
 
solving little problems
solving little problemssolving little problems
solving little problems
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 Spring
 
Metaprogramming in Haskell
Metaprogramming in HaskellMetaprogramming in Haskell
Metaprogramming in Haskell
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門
 
Groovy intro for OUDL
Groovy intro for OUDLGroovy intro for OUDL
Groovy intro for OUDL
 
Play á la Rails
Play á la RailsPlay á la Rails
Play á la Rails
 
Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09
 
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017 Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
 
Writing native bindings to node.js in C++
Writing native bindings to node.js in C++Writing native bindings to node.js in C++
Writing native bindings to node.js in C++
 
Javascript development done right
Javascript development done rightJavascript development done right
Javascript development done right
 

Kürzlich hochgeladen

Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
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
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
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
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
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
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
[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
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 

Kürzlich hochgeladen (20)

Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
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
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
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
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
[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
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 

Herding types with Scala macros

  • 1. H E R D I NG { T Y P E S } WITH SCALA #MACROS Marina Sigaeva
  • 3. ROADMAP ▸ How Java driver stores data in Aerospike
  • 4. ROADMAP ▸ How Java driver stores data in Aerospike ▸ What driver has to do
  • 5. ROADMAP ▸ How Java driver stores data in Aerospike ▸ What driver has to do ▸ The type safe solution with Scala macros
  • 6. KEY META BINS K1 (id,“Bob”) K2 Bin1, Bin2, .. BinN PEOPLE NS1 SET:
  • 7. KEY META BINS K1 (id,“Joe”) K2 Bin1, Bin2, .. BinN NS1 SET: PEOPLE
  • 8. KEY META BINS K1 (id,1234) K2 Bin1, Bin2, .. BinN NS1 SET: PEOPLE
  • 9. DS
  • 10. DS DS
  • 12. Java object DBConnector {
 
 val config = ConfigFactory.load()
 
 val hosts = List(config.getString("aerospike.host"))
 val port = config.getInt("aerospike.port")
 val namespace = config.getString("aerospike.namespace")
 val setName = config.getString("aerospike.setName")
 
 val database: AsyncClient = new AsyncClient(new AsyncClientPolicy, hosts.map(new Host(_, port)): _*)
 
 val key1 = new Key("namespace", "setName", new StringValue("key1"))
 val key2 = new Key("namespace", "setName", new StringValue("key2"))
 val key3 = new Key("namespace", "setName", new StringValue("key3"))
 
 database.put(new WritePolicy, key1, Seq(new Bin("bin1", new StringValue("abcd"))): _*) 
 database.put(new WritePolicy, key2, Seq(new Bin("bin2", new IntegerValue(2))): _*) 
 database.put(new WritePolicy, key3, Seq(new Bin("bin3", new BooleanValue(true))): _*) 
 
 val record1 = database.get(new BatchPolicy, key1)
 val record2 = database.get(new BatchPolicy, key2)
 val record3 = database.get(new BatchPolicy, key3)
 
 val res1 = longParsingFunction(record1)
 val res2 = longParsingFunction(record2)
 val res3 = longParsingFunction(record3)
 
 def longParsingFunction[T](record: Record): T = {
 val outValue: Map[String, Option[$tpe]] = {
 val jMap = record.bins.view collect {
 case (name, bt: Any) =>
 val res = fetch(bt)
 
 if (res.isEmpty && r.bins.nonEmpty) throw new Exception("Wrong type!")
 else name -> res

  • 13. Scalaobject DBConnector {
 
 val db = new Database()
 
 db.put("key1", "bin1", "abcd")
 db.put("key2", "bin2", 2)
 db.put("key3", "bin3", true) 
 
 val res1 = db.get[String]("key1")
 val res2 = db.get[Int]("key2")
 val res3 = db.get[Boolean]("key3")
 }
  • 15. package ru.tinkoff.example
 
 
 object DBConnector {
 …
 
 database.put(new WritePolicy,
 new Key("namespace", "setName", new StringValue("key1")),
 Seq(new Bin("binName1", new StringValue("binValue"))):_*)
 
 database.put(new WritePolicy,
 new Key("namespace", "setName", new StringValue("key2")),
 Seq(new Bin("binName2", new IntegerValue(2))):_*)
 
 database.put(new WritePolicy,
 new Key("namespace", "setName", new StringValue("key3")),
 Seq(new Bin("binName3", new BooleanValue(true))):_*)
 
 } 7 Key types 12 Bin types
  • 16. db.put("key1", "bin1", "abcd")
 
 db.put("key2", "bin2", 8)
 
 db.put("key3", "bin3", true)
 
 db.put("key4", "bin4", List(1.8, 33.8, 128)) db.put("key4", "bin4", List(true, false))
  • 17. db.put("key5", "cat", Cat("Rex", 2))
 
 db.put("key6", "trucks", 
 List(Truck("F1", 8), Truck("F2", 23), 
 Truck("F3", 11)))
 
 db.put("key7", "students",
 List(Student("Jack Green", A), 
 Student("Sara Lee", A),
 Student("Cameron Roonie", B)))
 db.put("key8", "hList”", "qwerty" :: 2 :: false :: HNil)
  • 18. db.put("key5", "cat", Cat("Rex", 2))
 
 db.put("key6", "trucks", 
 List(Truck("F1", 8), Truck("F2", 23), 
 Truck("F3", 11)))
 
 db.put("key7", "students",
 List(Student("Jack Green", A), 
 Student("Sara Lee", A),
 Student("Cameron Roonie", B)))
 db.put("key8", "hList”", "qwerty" :: 2 :: false :: HNil) UNLIMITED
  • 20. val hList = 123 :: "abcdef" :: true :: HNil +———————————————————————-+ | hList | +———————————————————————-+ | MAP('{"0":123, "1":"abcdef", "2":1}') | +———————————————————————-+ val cat0 = Cat("Lewis", 3) +—————————————————————-—-+ | cat0 | +———————————————————————+ | MAP('{"name":"Lewis", "age":3}') | +———————————————————————+
  • 22. get(policy: BatchPolicy, listener: BatchSequenceListener, records: util.List[Ba get(policy: BatchPolicy, listener: RecordSequenceListener, keys: Array[Key], b get(policy: BatchPolicy, listener: RecordArrayListener, keys: Array[Key], binN get(policy: BatchPolicy, listener: RecordSequenceListener, keys: Array[Key]) get(policy: BatchPolicy, listener: RecordArrayListener, keys: Array[Key])
 get(policy: Policy, listener: RecordListener, key: Key, binNames: String *)
 get(policy: Policy, listener: RecordListener, key: Key)
 get(policy: BatchPolicy, listener: BatchListListener, records: util.List[BatchRe get(policy: BatchPolicy, records: util.List[BatchRead])
 get(policy: BatchPolicy, keys: Array[Key], binNames: String *)
 get(policy: BatchPolicy, keys: Array[Key])
 get(policy: Policy, key: Key, binNames: String *)
 get(policy: Policy, key: Key) m m m m m m m m m m m m m
  • 24. public final class Record {
 //Map of requested name/value bins.
 
 public final Map<String,Object> bins;
 
 public final int generation;
 
 public final int expiration;
 
 …
 
 }
  • 25. val results = database.get(new BatchPolicy(), 
 new RecordArrayListener(),
 List("Lewis", "Mona", "Rex")
 .map(key => createKey(key)))
 .map(record => 
 longParsingCatFunction(record))
 
 
 def longParsingCatFunction[T](
 record: Record): Option[T] = {
 
 
 … 
 
 }
  • 27. WHAT DOES THE DRIVER HAVE TO DO?
  • 28. WHAT DOES THE DRIVER HAVE TO DO? ▸ More concise API
  • 29. WHAT DOES THE DRIVER HAVE TO DO? ▸ More concise API ▸ Take care of serialization
  • 30. WHAT DOES THE DRIVER HAVE TO DO? ▸ More concise API ▸ Take care of serialization ▸ To work out of the box
  • 32. def call[K, B](action: Action, key: K, bin: B)
 (implicit kw: KeyWrapper[K],
 bw: BinWrapper[B],
 pw: Option[WritePolicy] = None) = ???
  • 33. def call[K, B](action: Action, key: K, bin: B)
 (implicit kw: KeyWrapper[K],
 bw: BinWrapper[B],
 pw: Option[WritePolicy] = None) = ??? call(Put, “key”, “abcd”)
  • 34. def call[K, B](action: Action, key: K, bin: B)
 (implicit kw: KeyWrapper[K],
 bw: BinWrapper[B],
 pw: Option[WritePolicy] = None) = ??? call(Put, “key”, “abcd”)( new KeyWrapper[String]{},
 new BinWrapper[String]{}, None)
  • 35. def call[K, B](action: Action, key: K, bin: B)
 (implicit kw: KeyWrapper[K],
 bw: BinWrapper[B],
 pw: Option[WritePolicy] = None) = ??? def put[K, B](key: K, bin: B)(call(Put, key, bin))
 
 
 def get[K, B](key: K)(call(Get, key))
  • 36. trait KeyWrapper[K] {
 def apply(k: K): Key = new Key(toValue(k)) def toValue(v: K): Value = v match {
 case s: String => new StringValue(s)
 case h: HList => new MapValue(toMap(h))
 …
 }
 }
  • 37. new KeyWrapper[String] {
 def apply(k: String): Key = ???
 } 
 
 new KeyWrapper[HList] {
 def apply(k: HList): Key = ???
 } new KeyWrapper[ ] {
 def apply(k: ): Key = ???
 } new KeyWrapper[ ] {
 def apply(k: ): Key = ???
 }
  • 41. object KeyWrapper {
 
 implicit def materialize[K]: KeyWrapper[K] = macro implKey[K]
 
 def implKey[K: c.WeakTypeTag](c: Context): c.Expr[KeyWrapper[K]] = {
 import c.universe._
 val tpe = weakTypeOf[K] val imports = q""" 
 import com.aerospike.client.{Key, Value} """
 
 c.Expr[KeyWrapper[K]] {
 q""" 
 $imports
 new KeyWrapper[$tpe] {}
 """
 }
 }
 }
  • 42. object KeyWrapper {
 
 implicit def materialize[K]: KeyWrapper[K] = macro implKey[K]
 
 def implKey[K: c.WeakTypeTag](c: Context): c.Expr[KeyWrapper[K]] = {
 import c.universe._
 val tpe = weakTypeOf[K] val imports = q""" 
 import com.aerospike.client.{Key, Value} """
 
 c.Expr[KeyWrapper[K]] {
 q""" 
 $imports
 new KeyWrapper[$tpe] {}
 """
 }
 }
 }
  • 43. object KeyWrapper {
 
 implicit def materialize[K]: KeyWrapper[K] = macro implKey[K]
 
 def implKey[K: c.WeakTypeTag](c: Context): c.Expr[KeyWrapper[K]] = {
 import c.universe._
 val tpe = weakTypeOf[K] val imports = q""" 
 import com.aerospike.client.{Key, Value} """
 
 c.Expr[KeyWrapper[K]] {
 q""" 
 $imports
 new KeyWrapper[$tpe] {}
 """
 }
 }
 }
  • 45. object Usage {
 
 insertData({
 import com.aerospike.client.{Key, Value};
 { final class $anon extends KeyWrapper[String] { def <init>() = { super.<init>(); () }; <empty> }; new $anon() } }) }
  • 46. new KeyWrapper[String] new KeyWrapper[Int] new KeyWrapper[HList] new KeyWrapper[Cat]
  • 47. trait BinWrapper[B] { def apply(v: B): Bin = new Bin("name", toValue(v)) def toValue(v: B): Value = v match { case s: String => new StringValue(s) case h: HList => new MapValue(toMap(h)) case _ => throw new Exception("Wrong type") } def apply(r: Record): Map[String, B] = r.bins.collect { case (name, something) => name -> fetch(something) }.toMap def fetch(donkey: Any): B }
  • 48. trait BinWrapper[B] { def apply(v: B): Bin = new Bin("name", toValue(v)) def toValue(v: B): Value = v match { case s: String => new StringValue(s) case h: HList => new MapValue(toMap(h)) case _ => throw new Exception("Wrong type") } def apply(r: Record): Map[String, B] = r.bins.collect { case (name, something) => name -> fetch(something) }.toMap def fetch(donkey: Any): B }
  • 49. object BinWrapper {
 
 implicit def materialize[T]: BinWrapper[T] = macro matBin[T]
 
 def matBin[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[BinWrapper[T]] = {
 import c.universe._
 
 val tpe = weakTypeOf[T]
 
 val imports = q""" import …""" val fetchValue = ??? 
 c.Expr[BinWrapper[T]] {
 q""" $imports
 new BinWrapper[$tpe] { 
 $fetchValue 
 }""" 
 }
 }
 }
  • 50. object BinWrapper {
 
 implicit def materialize[T]: BinWrapper[T] = macro matBin[T]
 
 def matBin[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[BinWrapper[T]] = {
 import c.universe._
 
 val tpe = weakTypeOf[T]
 
 val imports = q""" import …""" val fetchValue = ??? 
 c.Expr[BinWrapper[T]] {
 q""" $imports
 new BinWrapper[$tpe] { 
 $fetchValue 
 }""" 
 }
 }
 }
  • 51. val tpe = weakTypeOf[T]
 
 val fetchValue = tpe match { case t if t =:= weakTypeOf[String] => q""" def fetch(any: Any): $tpe = any match { case v: String => v case _ => throw new Exception("Wrong type") } """ case t if isHList(t) => q""" def fetch(any: Any): $tpe = any match { case mv: MapValue => mv.getObject match { case m: Map[String, Any] => parse(m).toHList[$tpe].getOrElse{} case _ => throw new Exception("Wrong type") } case _ => throw new Exception("Wrong type") } """
 ... }
  • 52. Expr[ru.tinkoff.BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]]]({ import com.aerospike.client.{Key, Value}; import collection.JavaConversions._; import com.aerospike.client.Value._; import shapeless._; import syntax.std.traversable._; { final class $anon extends BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] { def <init>() = { super.<init>(); () }; def fetch(any: Any): shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]] = any match { case (mv @ (_: MapValue)) => mv.getObject match { case (m @ (_: Map[String, Any])) => parse(m).toHList[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]].getOrElse{} case _ => throw new Exception("Wrong type") } case _ => throw new Exception("Wrong type") } }; new $anon() } }) BinWrapper.matBin[Int::Boolean::HNil]
  • 53. Expr[ru.tinkoff.BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]]]({ import com.aerospike.client.{Key, Value}; import collection.JavaConversions._; import com.aerospike.client.Value._; import shapeless._; import syntax.std.traversable._; { final class $anon extends BinWrapper[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] { def <init>() = { super.<init>(); () }; def fetch(any: Any): shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]] = any match { case (mv @ (_: MapValue)) => mv.getObject match { case (m @ (_: Map[String, Any])) => parse(m).toHList[shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]].getOrElse{} case _ => throw new Exception("Wrong type") } case _ => throw new Exception("Wrong type") } }; new $anon() } }) }imports def fetch: Any => HL type HL = Int::Boolean::HNil
  • 54.
  • 55. def writeBin[B](b: B)
 (implicit bw: BinWrapper[B]): Bin = bw(b)
 
 
 val asMap = new BinWrapper[Truck] { }
 val asJson = new BinWrapper[Truck] { … }
 
 writeBin("tr1", Truck("truck1", 4,
 List(1, 2, 3)))(asMap)
 writeBin("tr2", Truck("truck2", 2,
 List(7, 8, 9)))(asJson)
  • 57. case class Sample(name: String, i: Int)
 
 db.put("intKey", "intBin", 202))
 
 db.put("hListKey", "hListBin",
 "abcd" :: 2 :: 3 :: HNil))
 
 db.put("mapKey", "mapBin",
 Map(Sample("t1", 3) -> "v1",
 Sample("t2", 2) -> "v2",
 Sample("t3", 1) -> "v3")))
  • 58. AQL > select * from test.test [ { "mapBin": {} }, { "intBin": 202 }, { "hListBin": { "0": "abcd", "1": 2, "2": 3 } }
  • 59. object CleanUp extends App {
 
 val keys = List("mapKey", "intKey", "hListKey")
 
 val res = Future.traverse(keys)(db.delete)
 }
  • 60. object CleanUp extends App {
 
 val keys = List("mapKey", "intKey", "hListKey")
 
 val res = Future.traverse(keys)(db.delete)
 } aql> select * from test.test [ ]
  • 61. aerospike-scala-dsl https://github.com/DanyMariaLee/aerospike-scala "ru.tinkoff" % "aerospike-scala" % "1.1.14",
 "ru.tinkoff" % "aerospike-scala-proto" % "1.1.14",
 "ru.tinkoff" % "aerospike-scala-example" % "1.1.14"