SlideShare una empresa de Scribd logo
1 de 63
Descargar para leer sin conexión
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

Más contenido relacionado

La actualidad más candente

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
 

La actualidad más candente (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
 

Similar a 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
 

Similar a 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
 

Último

Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 

Último (20)

Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 

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"