Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Typelevel summit

585 views

Published on

NoSQL and Scala macros

Published in: Engineering
  • Be the first to comment

Typelevel summit

  1. 1. HERDING {TYPES} WITH SCALA #MACROS Marina Sigaeva Typelevel Summit Copenhagen besselfunction@mail.ru @besseifunction
  2. 2. DATA => AEROSPIKE //TODO FOR DRIVER THE TYPE SAFE SOLUTION .roadMap { }
  3. 3. PEOPLE (id,“Bob”)Key1 Key2 Bin1 Bin2 BinN Int String Map
  4. 4. PEOPLE (id,1234)Key1 Key3 Bin1 Bin2 BinN Int Int Int
  5. 5. DS
  6. 6. DS DS
  7. 7. DS DS DS
  8. 8. data storing
  9. 9. 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 Java
  10. 10. Byte Int Long HList Case class Map Short Boolean Aerospike
  11. 11. val hList = 123 :: "abc" :: true :: HNil +———————————————————————-+ | hList | +———————————————————————-+ | MAP('{"0":123, "1":"abc", "2":1}') | +———————————————————————-+ val bunny = Bunny("Max", 1) +—————————————————————-—-+ | bunny | +———————————————————————+ | MAP('{"name":"Max", "age":1}') | +———————————————————————+
  12. 12. getting data
  13. 13. 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
  14. 14. public final class Record {
 
 public final Map<String,Object> bins;
 
 public final int generation;
 
 public final int expiration;
 
 …
 
 } DS
  15. 15. db.get[List[Bunny]](List("Max", "Peter", "Ruby"))
  16. 16. WHAT DOES THE DRIVER HAVE TO DO? MORE CONCISE API TAKE CARE OF SERIALIZATION TO WORK OUT OF THE BOX
  17. 17. implementation
  18. 18. 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")
  19. 19. 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)
  20. 20. 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 }
  21. 21. new BinWrapper[String] {
 def apply(v: String): Bin = ???
 } 
 
 new BinWrapper[Int] {
 def apply(v: Int): Bin = ???
 } new BinWrapper[ ] {
 def apply(v: ): Bin = ???
 }
  22. 22. Macros Context Symbol Type Tree
  23. 23. import c.universe._
 
 Apply(
 Select(Literal(Constant(1)), TermName("$plus")), 
 List(Literal(Constant(1)))
 ) q"1 + 1" 1 + 1
  24. 24. object BinWrapper {
 
 implicit def materialize[B]: BinWrapper[B] = macro matBin[B]
 
 def matBin[B: c.WeakTypeTag](c: blackbox.Context): c.Expr[BinWrapper[B]] = {
 import c.universe._
 
 val tpe = weakTypeOf[B]
 
 val imports = q""" import …""" val fetchValue = ??? 
 c.Expr[BinWrapper[B]] {
 q""" $imports
 new BinWrapper[$tpe] { 
 $fetchValue 
 }""" 
 }
 }
 }
  25. 25. val tpe = weakTypeOf[B]
 
 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") } """
 ... }
  26. 26. object Usage {
 insertData(materialize[Int::Boolean::HNil])
 }
  27. 27. import com.aerospike.client.{Bin, Value}; import shapeless._; { 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() } object Usage {
 
 insertData({ }) }
  28. 28. import com.aerospike.client.{Bin, Value}; import shapeless._; { 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 object Usage {
 
 insertData({ }) }
  29. 29. BinWrapper[String] BinWrapper[Int] BinWrapper[HList] BinWrapper[Bunny]
  30. 30. def writeBin[B](b: B)
 (implicit bw: BinWrapper[B]): Bin = bw(b)
 
 
 val asMap = new BinWrapper[Bunny] { }
 val asJson = new BinWrapper[Bunny] { … }
 
 writeBin("b1", Bunny("Max", 4))(asMap)
 writeBin("b2", Bunny("Ruby", 2))(asJson)
  31. 31. aerospike-scala-dsl github.com/DanyMariaLee/aerospike-scala "aerospike-scala"
 "aerospike-scala-proto" "aerospike-scala-example" "ru.tinkoff" "1.1.14"%% %{ } aerospike.com/launchpad/

×